mirror of
https://github.com/home-assistant/core
synced 2024-07-15 09:42:11 +02:00
Issue warning if glances server version is 2 (#105887)
* Issue warning if glances server version is 2 * Auto detect api version * Apply suggestions * Add HA version deprecation * Apply suggestions from code review * update config flow tests * Fix breaks in ha version --------- Co-authored-by: Martin Hjelmare <marhje52@gmail.com>
This commit is contained in:
parent
890615bb92
commit
2331f89936
@ -1,13 +1,34 @@
|
||||
"""The Glances component."""
|
||||
import logging
|
||||
from typing import Any
|
||||
|
||||
from glances_api import Glances
|
||||
from glances_api.exceptions import (
|
||||
GlancesApiAuthorizationError,
|
||||
GlancesApiError,
|
||||
GlancesApiNoDataAvailable,
|
||||
)
|
||||
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import CONF_NAME, CONF_VERIFY_SSL, Platform
|
||||
from homeassistant.const import (
|
||||
CONF_HOST,
|
||||
CONF_PASSWORD,
|
||||
CONF_PORT,
|
||||
CONF_SSL,
|
||||
CONF_USERNAME,
|
||||
CONF_VERIFY_SSL,
|
||||
Platform,
|
||||
)
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.exceptions import (
|
||||
ConfigEntryAuthFailed,
|
||||
ConfigEntryError,
|
||||
ConfigEntryNotReady,
|
||||
HomeAssistantError,
|
||||
)
|
||||
import homeassistant.helpers.config_validation as cv
|
||||
from homeassistant.helpers.httpx_client import get_async_client
|
||||
from homeassistant.helpers.issue_registry import IssueSeverity, async_create_issue
|
||||
|
||||
from .const import DOMAIN
|
||||
from .coordinator import GlancesDataUpdateCoordinator
|
||||
@ -16,10 +37,19 @@ PLATFORMS = [Platform.SENSOR]
|
||||
|
||||
CONFIG_SCHEMA = cv.removed(DOMAIN, raise_if_present=False)
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry) -> bool:
|
||||
"""Set up Glances from config entry."""
|
||||
api = get_api(hass, dict(config_entry.data))
|
||||
try:
|
||||
api = await get_api(hass, dict(config_entry.data))
|
||||
except GlancesApiAuthorizationError as err:
|
||||
raise ConfigEntryAuthFailed from err
|
||||
except GlancesApiError as err:
|
||||
raise ConfigEntryNotReady from err
|
||||
except ServerVersionMismatch as err:
|
||||
raise ConfigEntryError(err) from err
|
||||
coordinator = GlancesDataUpdateCoordinator(hass, config_entry, api)
|
||||
await coordinator.async_config_entry_first_refresh()
|
||||
|
||||
@ -39,8 +69,38 @@ async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
||||
return unload_ok
|
||||
|
||||
|
||||
def get_api(hass: HomeAssistant, entry_data: dict[str, Any]) -> Glances:
|
||||
async def get_api(hass: HomeAssistant, entry_data: dict[str, Any]) -> Glances:
|
||||
"""Return the api from glances_api."""
|
||||
entry_data.pop(CONF_NAME, None)
|
||||
httpx_client = get_async_client(hass, verify_ssl=entry_data[CONF_VERIFY_SSL])
|
||||
return Glances(httpx_client=httpx_client, **entry_data)
|
||||
for version in (3, 2):
|
||||
api = Glances(
|
||||
host=entry_data[CONF_HOST],
|
||||
port=entry_data[CONF_PORT],
|
||||
version=version,
|
||||
ssl=entry_data[CONF_SSL],
|
||||
username=entry_data.get(CONF_USERNAME),
|
||||
password=entry_data.get(CONF_PASSWORD),
|
||||
httpx_client=httpx_client,
|
||||
)
|
||||
try:
|
||||
await api.get_ha_sensor_data()
|
||||
except GlancesApiNoDataAvailable as err:
|
||||
_LOGGER.debug("Failed to connect to Glances API v%s: %s", version, err)
|
||||
continue
|
||||
if version == 2:
|
||||
async_create_issue(
|
||||
hass,
|
||||
DOMAIN,
|
||||
"deprecated_version",
|
||||
breaks_in_ha_version="2024.8.0",
|
||||
is_fixable=False,
|
||||
severity=IssueSeverity.WARNING,
|
||||
translation_key="deprecated_version",
|
||||
)
|
||||
_LOGGER.debug("Connected to Glances API v%s", version)
|
||||
return api
|
||||
raise ServerVersionMismatch("Could not connect to Glances API version 2 or 3")
|
||||
|
||||
|
||||
class ServerVersionMismatch(HomeAssistantError):
|
||||
"""Raise exception if we fail to connect to Glances API."""
|
||||
|
@ -21,15 +21,8 @@ from homeassistant.const import (
|
||||
)
|
||||
from homeassistant.data_entry_flow import FlowResult
|
||||
|
||||
from . import get_api
|
||||
from .const import (
|
||||
CONF_VERSION,
|
||||
DEFAULT_HOST,
|
||||
DEFAULT_PORT,
|
||||
DEFAULT_VERSION,
|
||||
DOMAIN,
|
||||
SUPPORTED_VERSIONS,
|
||||
)
|
||||
from . import ServerVersionMismatch, get_api
|
||||
from .const import DEFAULT_HOST, DEFAULT_PORT, DOMAIN
|
||||
|
||||
DATA_SCHEMA = vol.Schema(
|
||||
{
|
||||
@ -37,7 +30,6 @@ DATA_SCHEMA = vol.Schema(
|
||||
vol.Optional(CONF_USERNAME): str,
|
||||
vol.Optional(CONF_PASSWORD): str,
|
||||
vol.Required(CONF_PORT, default=DEFAULT_PORT): int,
|
||||
vol.Required(CONF_VERSION, default=DEFAULT_VERSION): vol.In(SUPPORTED_VERSIONS),
|
||||
vol.Optional(CONF_SSL, default=False): bool,
|
||||
vol.Optional(CONF_VERIFY_SSL, default=False): bool,
|
||||
}
|
||||
@ -65,9 +57,8 @@ class GlancesFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
|
||||
assert self._reauth_entry
|
||||
if user_input is not None:
|
||||
user_input = {**self._reauth_entry.data, **user_input}
|
||||
api = get_api(self.hass, user_input)
|
||||
try:
|
||||
await api.get_ha_sensor_data()
|
||||
await get_api(self.hass, user_input)
|
||||
except GlancesApiAuthorizationError:
|
||||
errors["base"] = "invalid_auth"
|
||||
except GlancesApiConnectionError:
|
||||
@ -101,12 +92,11 @@ class GlancesFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
|
||||
self._async_abort_entries_match(
|
||||
{CONF_HOST: user_input[CONF_HOST], CONF_PORT: user_input[CONF_PORT]}
|
||||
)
|
||||
api = get_api(self.hass, user_input)
|
||||
try:
|
||||
await api.get_ha_sensor_data()
|
||||
await get_api(self.hass, user_input)
|
||||
except GlancesApiAuthorizationError:
|
||||
errors["base"] = "invalid_auth"
|
||||
except GlancesApiConnectionError:
|
||||
except (GlancesApiConnectionError, ServerVersionMismatch):
|
||||
errors["base"] = "cannot_connect"
|
||||
else:
|
||||
return self.async_create_entry(
|
||||
|
@ -8,9 +8,6 @@ CONF_VERSION = "version"
|
||||
|
||||
DEFAULT_HOST = "localhost"
|
||||
DEFAULT_PORT = 61208
|
||||
DEFAULT_VERSION = 3
|
||||
DEFAULT_SCAN_INTERVAL = timedelta(seconds=60)
|
||||
|
||||
SUPPORTED_VERSIONS = [2, 3]
|
||||
|
||||
CPU_ICON = f"mdi:cpu-{64 if sys.maxsize > 2**32 else 32}-bit"
|
||||
|
@ -7,7 +7,6 @@
|
||||
"username": "[%key:common::config_flow::data::username%]",
|
||||
"password": "[%key:common::config_flow::data::password%]",
|
||||
"port": "[%key:common::config_flow::data::port%]",
|
||||
"version": "Glances API Version (2 or 3)",
|
||||
"ssl": "[%key:common::config_flow::data::ssl%]",
|
||||
"verify_ssl": "[%key:common::config_flow::data::verify_ssl%]"
|
||||
},
|
||||
@ -30,5 +29,11 @@
|
||||
"already_configured": "[%key:common::config_flow::abort::already_configured_device%]",
|
||||
"reauth_successful": "[%key:common::config_flow::abort::reauth_successful%]"
|
||||
}
|
||||
},
|
||||
"issues": {
|
||||
"deprecated_version": {
|
||||
"title": "Glances servers with version 2 is deprecated",
|
||||
"description": "Glances servers with version 2 is deprecated and will not be supported in future versions of HA. It is recommended to update your server to Glances version 3 then reload the integration."
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -6,7 +6,6 @@ MOCK_USER_INPUT: dict[str, Any] = {
|
||||
"host": "0.0.0.0",
|
||||
"username": "username",
|
||||
"password": "password",
|
||||
"version": 3,
|
||||
"port": 61208,
|
||||
"ssl": False,
|
||||
"verify_ssl": True,
|
||||
|
@ -4,6 +4,7 @@ from unittest.mock import MagicMock
|
||||
from glances_api.exceptions import (
|
||||
GlancesApiAuthorizationError,
|
||||
GlancesApiConnectionError,
|
||||
GlancesApiNoDataAvailable,
|
||||
)
|
||||
import pytest
|
||||
|
||||
@ -47,6 +48,7 @@ async def test_form(hass: HomeAssistant) -> None:
|
||||
[
|
||||
(GlancesApiAuthorizationError, "invalid_auth"),
|
||||
(GlancesApiConnectionError, "cannot_connect"),
|
||||
(GlancesApiNoDataAvailable, "cannot_connect"),
|
||||
],
|
||||
)
|
||||
async def test_form_fails(
|
||||
@ -54,7 +56,7 @@ async def test_form_fails(
|
||||
) -> None:
|
||||
"""Test flow fails when api exception is raised."""
|
||||
|
||||
mock_api.return_value.get_ha_sensor_data.side_effect = [error, HA_SENSOR_DATA]
|
||||
mock_api.return_value.get_ha_sensor_data.side_effect = error
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
glances.DOMAIN, context={"source": config_entries.SOURCE_USER}
|
||||
)
|
||||
@ -65,12 +67,6 @@ async def test_form_fails(
|
||||
assert result["type"] == FlowResultType.FORM
|
||||
assert result["errors"] == {"base": message}
|
||||
|
||||
result = await hass.config_entries.flow.async_configure(
|
||||
result["flow_id"], user_input=MOCK_USER_INPUT
|
||||
)
|
||||
|
||||
assert result["type"] == FlowResultType.CREATE_ENTRY
|
||||
|
||||
|
||||
async def test_form_already_configured(hass: HomeAssistant) -> None:
|
||||
"""Test host is already configured."""
|
||||
|
@ -1,17 +1,19 @@
|
||||
"""Tests for Glances integration."""
|
||||
from unittest.mock import MagicMock
|
||||
from unittest.mock import AsyncMock, MagicMock
|
||||
|
||||
from glances_api.exceptions import (
|
||||
GlancesApiAuthorizationError,
|
||||
GlancesApiConnectionError,
|
||||
GlancesApiNoDataAvailable,
|
||||
)
|
||||
import pytest
|
||||
|
||||
from homeassistant.components.glances.const import DOMAIN
|
||||
from homeassistant.config_entries import ConfigEntryState
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers import issue_registry as ir
|
||||
|
||||
from . import MOCK_USER_INPUT
|
||||
from . import HA_SENSOR_DATA, MOCK_USER_INPUT
|
||||
|
||||
from tests.common import MockConfigEntry
|
||||
|
||||
@ -27,11 +29,34 @@ async def test_successful_config_entry(hass: HomeAssistant) -> None:
|
||||
assert entry.state == ConfigEntryState.LOADED
|
||||
|
||||
|
||||
async def test_entry_deprecated_version(
|
||||
hass: HomeAssistant, issue_registry: ir.IssueRegistry, mock_api: AsyncMock
|
||||
) -> None:
|
||||
"""Test creating an issue if glances server is version 2."""
|
||||
entry = MockConfigEntry(domain=DOMAIN, data=MOCK_USER_INPUT)
|
||||
entry.add_to_hass(hass)
|
||||
|
||||
mock_api.return_value.get_ha_sensor_data.side_effect = [
|
||||
GlancesApiNoDataAvailable("endpoint: 'all' is not valid"),
|
||||
HA_SENSOR_DATA,
|
||||
HA_SENSOR_DATA,
|
||||
]
|
||||
|
||||
await hass.config_entries.async_setup(entry.entry_id)
|
||||
|
||||
assert entry.state == ConfigEntryState.LOADED
|
||||
|
||||
issue = issue_registry.async_get_issue(DOMAIN, "deprecated_version")
|
||||
assert issue is not None
|
||||
assert issue.severity == ir.IssueSeverity.WARNING
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("error", "entry_state"),
|
||||
[
|
||||
(GlancesApiAuthorizationError, ConfigEntryState.SETUP_ERROR),
|
||||
(GlancesApiConnectionError, ConfigEntryState.SETUP_RETRY),
|
||||
(GlancesApiNoDataAvailable, ConfigEntryState.SETUP_ERROR),
|
||||
],
|
||||
)
|
||||
async def test_setup_error(
|
||||
|
Loading…
Reference in New Issue
Block a user