From bc2017a9b49f43474aa720c0ff5ffaed7198d847 Mon Sep 17 00:00:00 2001 From: Erwin Douna Date: Sat, 4 Jul 2026 22:04:35 +0200 Subject: [PATCH] Proxmox clean up import code (#175557) --- .../components/proxmoxve/__init__.py | 130 +----------------- .../components/proxmoxve/config_flow.py | 24 ---- .../components/proxmoxve/strings.json | 22 --- .../components/proxmoxve/test_config_flow.py | 81 +---------- tests/components/proxmoxve/test_init.py | 46 +------ 5 files changed, 7 insertions(+), 296 deletions(-) diff --git a/homeassistant/components/proxmoxve/__init__.py b/homeassistant/components/proxmoxve/__init__.py index 2f969fae5bed..291a6c298e31 100644 --- a/homeassistant/components/proxmoxve/__init__.py +++ b/homeassistant/components/proxmoxve/__init__.py @@ -2,43 +2,17 @@ import logging -import voluptuous as vol - -from homeassistant.config_entries import SOURCE_IMPORT -from homeassistant.const import ( - CONF_HOST, - CONF_PASSWORD, - CONF_PORT, - CONF_TOKEN, - CONF_USERNAME, - CONF_VERIFY_SSL, - Platform, -) -from homeassistant.core import DOMAIN as HOMEASSISTANT_DOMAIN, HomeAssistant -from homeassistant.data_entry_flow import FlowResultType -from homeassistant.helpers import ( - config_validation as cv, - entity_registry as er, - issue_registry as ir, -) -from homeassistant.helpers.typing import ConfigType +from homeassistant.const import CONF_TOKEN, CONF_USERNAME, Platform +from homeassistant.core import HomeAssistant +from homeassistant.helpers import entity_registry as er from .const import ( AUTH_OTHER, AUTH_PAM, AUTH_PVE, CONF_AUTH_METHOD, - CONF_CONTAINERS, - CONF_NODE, - CONF_NODES, CONF_REALM, - CONF_TOKEN_ID, - CONF_TOKEN_SECRET, - CONF_VMS, - DEFAULT_PORT, DEFAULT_REALM, - DEFAULT_VERIFY_SSL, - DOMAIN, ) from .coordinator import ProxmoxConfigEntry, ProxmoxCoordinator @@ -49,107 +23,9 @@ PLATFORMS = [ ] -CONFIG_SCHEMA = vol.Schema( - { - DOMAIN: vol.All( - cv.ensure_list, - [ - vol.Schema( - { - vol.Required(CONF_HOST): cv.string, - vol.Required(CONF_USERNAME): cv.string, - vol.Optional(CONF_PASSWORD): cv.string, - vol.Optional(CONF_PORT, default=DEFAULT_PORT): cv.port, - vol.Required( - CONF_AUTH_METHOD, default=DEFAULT_REALM - ): cv.string, - vol.Optional(CONF_REALM, default=DEFAULT_REALM): cv.string, - vol.Optional(CONF_TOKEN, default=False): cv.boolean, - vol.Optional(CONF_TOKEN_ID): cv.string, - vol.Optional(CONF_TOKEN_SECRET): cv.string, - vol.Optional( - CONF_VERIFY_SSL, default=DEFAULT_VERIFY_SSL - ): cv.boolean, - vol.Required(CONF_NODES): vol.All( - cv.ensure_list, - [ - vol.Schema( - { - vol.Required(CONF_NODE): cv.string, - vol.Optional(CONF_VMS, default=[]): [ - cv.positive_int - ], - vol.Optional(CONF_CONTAINERS, default=[]): [ - cv.positive_int - ], - } - ) - ], - ), - } - ) - ], - ) - }, - extra=vol.ALLOW_EXTRA, -) - _LOGGER = logging.getLogger(__name__) -async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool: - """Import the Proxmox configuration from YAML.""" - if DOMAIN not in config: - return True - - hass.async_create_task(_async_setup(hass, config)) - - return True - - -async def _async_setup(hass: HomeAssistant, config: ConfigType) -> None: - for entry_config in config[DOMAIN]: - result = await hass.config_entries.flow.async_init( - DOMAIN, - context={"source": SOURCE_IMPORT}, - data=entry_config, - ) - if ( - result.get("type") is FlowResultType.ABORT - and result.get("reason") != "already_configured" - ): - ir.async_create_issue( - hass, - DOMAIN, - f"deprecated_yaml_import_issue_{result.get('reason')}", - breaks_in_ha_version="2026.8.0", - is_fixable=False, - issue_domain=DOMAIN, - severity=ir.IssueSeverity.WARNING, - translation_key=f"deprecated_yaml_import_issue_{result.get('reason')}", - translation_placeholders={ - "domain": DOMAIN, - "integration_title": "Proxmox VE", - }, - ) - return - - ir.async_create_issue( - hass, - HOMEASSISTANT_DOMAIN, - "deprecated_yaml", - breaks_in_ha_version="2026.8.0", - is_fixable=False, - issue_domain=DOMAIN, - severity=ir.IssueSeverity.WARNING, - translation_key="deprecated_yaml", - translation_placeholders={ - "domain": DOMAIN, - "integration_title": "Proxmox VE", - }, - ) - - async def async_setup_entry(hass: HomeAssistant, entry: ProxmoxConfigEntry) -> bool: """Set up a ProxmoxVE from a config entry.""" coordinator = ProxmoxCoordinator(hass, entry) diff --git a/homeassistant/components/proxmoxve/config_flow.py b/homeassistant/components/proxmoxve/config_flow.py index 565c37300fe5..14c4086f6a61 100644 --- a/homeassistant/components/proxmoxve/config_flow.py +++ b/homeassistant/components/proxmoxve/config_flow.py @@ -356,30 +356,6 @@ class ProxmoxveConfigFlow(ConfigFlow, domain=DOMAIN): return proxmox_nodes, errors - async def async_step_import(self, import_data: dict[str, Any]) -> ConfigFlowResult: - """Handle a flow initiated by configuration file.""" - self._async_abort_entries_match({CONF_HOST: import_data[CONF_HOST]}) - - try: - proxmox_nodes = await self.hass.async_add_executor_job( - _get_nodes_data, import_data - ) - except ProxmoxConnectTimeout: - return self.async_abort(reason="connect_timeout") - except ProxmoxAuthenticationError: - return self.async_abort(reason="invalid_auth") - except ProxmoxSSLError: - return self.async_abort(reason="ssl_error") - except ProxmoxNoNodesFound: - return self.async_abort(reason="no_nodes_found") - except ProxmoxConnectionError: - return self.async_abort(reason="cannot_connect") - - return self.async_create_entry( - title=import_data[CONF_HOST], - data={**import_data, CONF_NODES: proxmox_nodes}, - ) - def _get_auth_schema( self, data: Mapping[str, Any], diff --git a/homeassistant/components/proxmoxve/strings.json b/homeassistant/components/proxmoxve/strings.json index a92e6ef4506f..62316d3508e0 100644 --- a/homeassistant/components/proxmoxve/strings.json +++ b/homeassistant/components/proxmoxve/strings.json @@ -342,28 +342,6 @@ "message": "A timeout occurred while trying to connect to the Proxmox VE instance." } }, - "issues": { - "deprecated_yaml_import_issue_cannot_connect": { - "description": "Configuring {integration_title} via YAML is deprecated and will be removed in a future release. While importing your configuration, a connection error occurred. Please correct your YAML configuration and restart Home Assistant, or remove the {domain} key from your configuration and configure the integration via the UI.", - "title": "[%key:component::proxmoxve::issues::deprecated_yaml_import_issue_connect_timeout::title%]" - }, - "deprecated_yaml_import_issue_connect_timeout": { - "description": "Configuring {integration_title} via YAML is deprecated and will be removed in a future release. While importing your configuration, a connection timeout occurred. Please correct your YAML configuration and restart Home Assistant, or remove the {domain} key from your configuration and configure the integration via the UI.", - "title": "The {integration_title} YAML configuration is being removed" - }, - "deprecated_yaml_import_issue_invalid_auth": { - "description": "Configuring {integration_title} via YAML is deprecated and will be removed in a future release. While importing your configuration, invalid authentication details were found. Please correct your YAML configuration and restart Home Assistant, or remove the {domain} key from your configuration and configure the integration via the UI.", - "title": "[%key:component::proxmoxve::issues::deprecated_yaml_import_issue_connect_timeout::title%]" - }, - "deprecated_yaml_import_issue_no_nodes_found": { - "description": "Configuring {integration_title} via YAML is deprecated and will be removed in a future release. While importing your configuration, no active nodes were found on the Proxmox VE server. Please correct your YAML configuration and restart Home Assistant, or remove the {domain} key from your configuration and configure the integration via the UI.", - "title": "[%key:component::proxmoxve::issues::deprecated_yaml_import_issue_connect_timeout::title%]" - }, - "deprecated_yaml_import_issue_ssl_error": { - "description": "Configuring {integration_title} via YAML is deprecated and will be removed in a future release. While importing your configuration, an SSL error occurred. Please correct your YAML configuration and restart Home Assistant, or remove the {domain} key from your configuration and configure the integration via the UI.", - "title": "[%key:component::proxmoxve::issues::deprecated_yaml_import_issue_connect_timeout::title%]" - } - }, "selector": { "auth_method": { "options": { diff --git a/tests/components/proxmoxve/test_config_flow.py b/tests/components/proxmoxve/test_config_flow.py index c6814ca95717..981332352929 100644 --- a/tests/components/proxmoxve/test_config_flow.py +++ b/tests/components/proxmoxve/test_config_flow.py @@ -9,7 +9,7 @@ import pytest import requests from requests.exceptions import ConnectTimeout, SSLError -from homeassistant.components.proxmoxve import CONF_AUTH_METHOD, CONF_HOST, CONF_REALM +from homeassistant.components.proxmoxve import CONF_AUTH_METHOD, CONF_REALM from homeassistant.components.proxmoxve.const import ( CONF_NODE, CONF_NODES, @@ -17,8 +17,9 @@ from homeassistant.components.proxmoxve.const import ( CONF_TOKEN_SECRET, DOMAIN, ) -from homeassistant.config_entries import SOURCE_IMPORT, SOURCE_USER, ConfigEntryState +from homeassistant.config_entries import SOURCE_USER from homeassistant.const import ( + CONF_HOST, CONF_PASSWORD, CONF_PORT, CONF_TOKEN, @@ -424,82 +425,6 @@ async def test_duplicate_entry( assert result["reason"] == "already_configured" -async def test_import_flow( - hass: HomeAssistant, - mock_setup_entry: MagicMock, - mock_proxmox_client: MagicMock, -) -> None: - """Test importing from YAML creates a config entry and sets it up.""" - MOCK_IMPORT_CONFIG = { - DOMAIN: { - **MOCK_USER_STEP, - **MOCK_USER_AUTH_STEP_PASSWORD, - **MOCK_USER_SETUP, - } - } - result = await hass.config_entries.flow.async_init( - DOMAIN, context={"source": SOURCE_IMPORT}, data=MOCK_IMPORT_CONFIG[DOMAIN] - ) - - assert result["type"] is FlowResultType.CREATE_ENTRY - assert result["title"] == "127.0.0.1" - assert result["data"][CONF_HOST] == "127.0.0.1" - assert len(mock_setup_entry.mock_calls) == 1 - - assert result["result"].state is ConfigEntryState.LOADED - - -@pytest.mark.parametrize( - ("exception", "reason"), - [ - ( - AuthenticationError("Invalid credentials"), - "invalid_auth", - ), - ( - SSLError("SSL handshake failed"), - "ssl_error", - ), - ( - ConnectTimeout("Connection timed out"), - "connect_timeout", - ), - ( - ResourceException("404", "status_message", "content"), - "no_nodes_found", - ), - ( - requests.exceptions.ConnectionError("Connection error"), - "cannot_connect", - ), - ], -) -async def test_import_flow_exceptions( - hass: HomeAssistant, - mock_setup_entry: MagicMock, - mock_proxmox_client: MagicMock, - exception: Exception, - reason: str, -) -> None: - """Test importing from YAML creates a config entry and sets it up.""" - MOCK_IMPORT_CONFIG = { - DOMAIN: { - **MOCK_USER_STEP, - **MOCK_USER_AUTH_STEP_PASSWORD, - **MOCK_USER_SETUP, - } - } - mock_proxmox_client.nodes.get.side_effect = exception - result = await hass.config_entries.flow.async_init( - DOMAIN, context={"source": SOURCE_IMPORT}, data=MOCK_IMPORT_CONFIG[DOMAIN] - ) - - assert result["type"] is FlowResultType.ABORT - assert result["reason"] == reason - assert len(mock_setup_entry.mock_calls) == 0 - assert len(hass.config_entries.async_entries(DOMAIN)) == 0 - - def sanitize_config_entry(data: dict[str, Any]) -> dict[str, Any]: """Sanitize config entry data by removing unused auth keys.""" # Ignore unused keys (i.e. when switching from password to token or vice versa) diff --git a/tests/components/proxmoxve/test_init.py b/tests/components/proxmoxve/test_init.py index 7c3aa0fac2af..d55afccaa03c 100644 --- a/tests/components/proxmoxve/test_init.py +++ b/tests/components/proxmoxve/test_init.py @@ -11,11 +11,7 @@ from requests.exceptions import ConnectTimeout, SSLError from homeassistant.components.proxmoxve.const import ( AUTH_PAM, CONF_AUTH_METHOD, - CONF_CONTAINERS, - CONF_NODE, - CONF_NODES, CONF_REALM, - CONF_VMS, DOMAIN, ) from homeassistant.components.proxmoxve.coordinator import ( @@ -32,54 +28,14 @@ from homeassistant.const import ( STATE_OFF, STATE_ON, ) -from homeassistant.core import DOMAIN as HOMEASSISTANT_DOMAIN, HomeAssistant +from homeassistant.core import HomeAssistant from homeassistant.helpers import device_registry as dr, entity_registry as er -import homeassistant.helpers.issue_registry as ir -from homeassistant.setup import async_setup_component from . import setup_integration from tests.common import MockConfigEntry, async_load_json_array_fixture -@pytest.mark.usefixtures("mock_setup_entry") -async def test_config_import( - hass: HomeAssistant, - mock_proxmox_client: MagicMock, - issue_registry: ir.IssueRegistry, -) -> None: - """Test sensor initialization.""" - await async_setup_component( - hass, - DOMAIN, - { - DOMAIN: [ - { - CONF_HOST: "127.0.0.1", - CONF_PORT: 8006, - CONF_REALM: "pam", - CONF_USERNAME: "test_user@pam", - CONF_PASSWORD: "test_password", - CONF_VERIFY_SSL: True, - CONF_NODES: [ - { - CONF_NODE: "pve1", - CONF_VMS: [100, 101], - CONF_CONTAINERS: [200, 201], - }, - ], - } - ] - }, - ) - - await hass.async_block_till_done() - - assert len(issue_registry.issues) == 1 - assert (HOMEASSISTANT_DOMAIN, "deprecated_yaml") in issue_registry.issues - assert len(hass.config_entries.async_entries(DOMAIN)) == 1 - - @pytest.mark.parametrize( ("exception", "expected_state", "target"), [