mirror of
https://github.com/home-assistant/core.git
synced 2025-04-26 18:27:51 +00:00
DNS IP custom ports for IPv4 (#113993)
* squash DNS IP enable port * linting * fix config entries in tests. * fix more config entries * fix parameter order * Add defaults for legacy config entries * test legacy config are not broken * test driven migration * define versions for future proofing * remove defaults as should be covered by migrations in the future * adds config migration * spacing * Review: remove unnecessary statements Co-authored-by: G Johansson <goran.johansson@shiftit.se> * Apply suggestions from code review Co-authored-by: G Johansson <goran.johansson@shiftit.se> * make default ports the same * test migration from future error * linting * Small tweaks --------- Co-authored-by: G Johansson <goran.johansson@shiftit.se>
This commit is contained in:
parent
9723b97f4b
commit
adcd0cc2a4
@ -3,9 +3,10 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from homeassistant.config_entries import ConfigEntry
|
from homeassistant.config_entries import ConfigEntry
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.const import CONF_PORT
|
||||||
|
from homeassistant.core import _LOGGER, HomeAssistant
|
||||||
|
|
||||||
from .const import PLATFORMS
|
from .const import CONF_PORT_IPV6, DEFAULT_PORT, PLATFORMS
|
||||||
|
|
||||||
|
|
||||||
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
||||||
@ -25,3 +26,36 @@ async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
|||||||
"""Unload dnsip config entry."""
|
"""Unload dnsip config entry."""
|
||||||
|
|
||||||
return await hass.config_entries.async_unload_platforms(entry, PLATFORMS)
|
return await hass.config_entries.async_unload_platforms(entry, PLATFORMS)
|
||||||
|
|
||||||
|
|
||||||
|
async def async_migrate_entry(hass: HomeAssistant, config_entry: ConfigEntry) -> bool:
|
||||||
|
"""Migrate old entry to a newer version."""
|
||||||
|
|
||||||
|
if config_entry.version > 1:
|
||||||
|
# This means the user has downgraded from a future version
|
||||||
|
return False
|
||||||
|
|
||||||
|
if config_entry.version < 2 and config_entry.minor_version < 2:
|
||||||
|
version = config_entry.version
|
||||||
|
minor_version = config_entry.minor_version
|
||||||
|
_LOGGER.debug(
|
||||||
|
"Migrating configuration from version %s.%s",
|
||||||
|
version,
|
||||||
|
minor_version,
|
||||||
|
)
|
||||||
|
|
||||||
|
new_options = {**config_entry.options}
|
||||||
|
new_options[CONF_PORT] = DEFAULT_PORT
|
||||||
|
new_options[CONF_PORT_IPV6] = DEFAULT_PORT
|
||||||
|
|
||||||
|
hass.config_entries.async_update_entry(
|
||||||
|
config_entry, options=new_options, minor_version=2
|
||||||
|
)
|
||||||
|
|
||||||
|
_LOGGER.debug(
|
||||||
|
"Migration to configuration version %s.%s successful",
|
||||||
|
1,
|
||||||
|
2,
|
||||||
|
)
|
||||||
|
|
||||||
|
return True
|
||||||
|
@ -16,7 +16,7 @@ from homeassistant.config_entries import (
|
|||||||
ConfigFlowResult,
|
ConfigFlowResult,
|
||||||
OptionsFlowWithConfigEntry,
|
OptionsFlowWithConfigEntry,
|
||||||
)
|
)
|
||||||
from homeassistant.const import CONF_NAME
|
from homeassistant.const import CONF_NAME, CONF_PORT
|
||||||
from homeassistant.core import callback
|
from homeassistant.core import callback
|
||||||
import homeassistant.helpers.config_validation as cv
|
import homeassistant.helpers.config_validation as cv
|
||||||
|
|
||||||
@ -25,10 +25,12 @@ from .const import (
|
|||||||
CONF_IPV4,
|
CONF_IPV4,
|
||||||
CONF_IPV6,
|
CONF_IPV6,
|
||||||
CONF_IPV6_V4,
|
CONF_IPV6_V4,
|
||||||
|
CONF_PORT_IPV6,
|
||||||
CONF_RESOLVER,
|
CONF_RESOLVER,
|
||||||
CONF_RESOLVER_IPV6,
|
CONF_RESOLVER_IPV6,
|
||||||
DEFAULT_HOSTNAME,
|
DEFAULT_HOSTNAME,
|
||||||
DEFAULT_NAME,
|
DEFAULT_NAME,
|
||||||
|
DEFAULT_PORT,
|
||||||
DEFAULT_RESOLVER,
|
DEFAULT_RESOLVER,
|
||||||
DEFAULT_RESOLVER_IPV6,
|
DEFAULT_RESOLVER_IPV6,
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
@ -42,32 +44,42 @@ DATA_SCHEMA = vol.Schema(
|
|||||||
DATA_SCHEMA_ADV = vol.Schema(
|
DATA_SCHEMA_ADV = vol.Schema(
|
||||||
{
|
{
|
||||||
vol.Required(CONF_HOSTNAME, default=DEFAULT_HOSTNAME): cv.string,
|
vol.Required(CONF_HOSTNAME, default=DEFAULT_HOSTNAME): cv.string,
|
||||||
vol.Optional(CONF_RESOLVER, default=DEFAULT_RESOLVER): cv.string,
|
vol.Optional(CONF_RESOLVER): cv.string,
|
||||||
vol.Optional(CONF_RESOLVER_IPV6, default=DEFAULT_RESOLVER_IPV6): cv.string,
|
vol.Optional(CONF_PORT): cv.port,
|
||||||
|
vol.Optional(CONF_RESOLVER_IPV6): cv.string,
|
||||||
|
vol.Optional(CONF_PORT_IPV6): cv.port,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
async def async_validate_hostname(
|
async def async_validate_hostname(
|
||||||
hostname: str, resolver_ipv4: str, resolver_ipv6: str
|
hostname: str,
|
||||||
|
resolver_ipv4: str,
|
||||||
|
resolver_ipv6: str,
|
||||||
|
port: int,
|
||||||
|
port_ipv6: int,
|
||||||
) -> dict[str, bool]:
|
) -> dict[str, bool]:
|
||||||
"""Validate hostname."""
|
"""Validate hostname."""
|
||||||
|
|
||||||
async def async_check(hostname: str, resolver: str, qtype: str) -> bool:
|
async def async_check(
|
||||||
|
hostname: str, resolver: str, qtype: str, port: int = 53
|
||||||
|
) -> bool:
|
||||||
"""Return if able to resolve hostname."""
|
"""Return if able to resolve hostname."""
|
||||||
result = False
|
result = False
|
||||||
with contextlib.suppress(DNSError):
|
with contextlib.suppress(DNSError):
|
||||||
result = bool(
|
result = bool(
|
||||||
await aiodns.DNSResolver(nameservers=[resolver]).query(hostname, qtype)
|
await aiodns.DNSResolver(
|
||||||
|
nameservers=[resolver], udp_port=port, tcp_port=port
|
||||||
|
).query(hostname, qtype)
|
||||||
)
|
)
|
||||||
return result
|
return result
|
||||||
|
|
||||||
result: dict[str, bool] = {}
|
result: dict[str, bool] = {}
|
||||||
|
|
||||||
tasks = await asyncio.gather(
|
tasks = await asyncio.gather(
|
||||||
async_check(hostname, resolver_ipv4, "A"),
|
async_check(hostname, resolver_ipv4, "A", port=port),
|
||||||
async_check(hostname, resolver_ipv6, "AAAA"),
|
async_check(hostname, resolver_ipv6, "AAAA", port=port_ipv6),
|
||||||
async_check(hostname, resolver_ipv4, "AAAA"),
|
async_check(hostname, resolver_ipv4, "AAAA", port=port),
|
||||||
)
|
)
|
||||||
|
|
||||||
result[CONF_IPV4] = tasks[0]
|
result[CONF_IPV4] = tasks[0]
|
||||||
@ -81,6 +93,7 @@ class DnsIPConfigFlow(ConfigFlow, domain=DOMAIN):
|
|||||||
"""Handle a config flow for dnsip integration."""
|
"""Handle a config flow for dnsip integration."""
|
||||||
|
|
||||||
VERSION = 1
|
VERSION = 1
|
||||||
|
MINOR_VERSION = 2
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
@callback
|
@callback
|
||||||
@ -102,8 +115,12 @@ class DnsIPConfigFlow(ConfigFlow, domain=DOMAIN):
|
|||||||
name = DEFAULT_NAME if hostname == DEFAULT_HOSTNAME else hostname
|
name = DEFAULT_NAME if hostname == DEFAULT_HOSTNAME else hostname
|
||||||
resolver = user_input.get(CONF_RESOLVER, DEFAULT_RESOLVER)
|
resolver = user_input.get(CONF_RESOLVER, DEFAULT_RESOLVER)
|
||||||
resolver_ipv6 = user_input.get(CONF_RESOLVER_IPV6, DEFAULT_RESOLVER_IPV6)
|
resolver_ipv6 = user_input.get(CONF_RESOLVER_IPV6, DEFAULT_RESOLVER_IPV6)
|
||||||
|
port = user_input.get(CONF_PORT, DEFAULT_PORT)
|
||||||
|
port_ipv6 = user_input.get(CONF_PORT_IPV6, DEFAULT_PORT)
|
||||||
|
|
||||||
validate = await async_validate_hostname(hostname, resolver, resolver_ipv6)
|
validate = await async_validate_hostname(
|
||||||
|
hostname, resolver, resolver_ipv6, port, port_ipv6
|
||||||
|
)
|
||||||
|
|
||||||
set_resolver = resolver
|
set_resolver = resolver
|
||||||
if validate[CONF_IPV6]:
|
if validate[CONF_IPV6]:
|
||||||
@ -129,7 +146,9 @@ class DnsIPConfigFlow(ConfigFlow, domain=DOMAIN):
|
|||||||
},
|
},
|
||||||
options={
|
options={
|
||||||
CONF_RESOLVER: resolver,
|
CONF_RESOLVER: resolver,
|
||||||
|
CONF_PORT: port,
|
||||||
CONF_RESOLVER_IPV6: set_resolver,
|
CONF_RESOLVER_IPV6: set_resolver,
|
||||||
|
CONF_PORT_IPV6: port_ipv6,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -156,11 +175,15 @@ class DnsIPOptionsFlowHandler(OptionsFlowWithConfigEntry):
|
|||||||
errors = {}
|
errors = {}
|
||||||
if user_input is not None:
|
if user_input is not None:
|
||||||
resolver = user_input.get(CONF_RESOLVER, DEFAULT_RESOLVER)
|
resolver = user_input.get(CONF_RESOLVER, DEFAULT_RESOLVER)
|
||||||
|
port = user_input.get(CONF_PORT, DEFAULT_PORT)
|
||||||
resolver_ipv6 = user_input.get(CONF_RESOLVER_IPV6, DEFAULT_RESOLVER_IPV6)
|
resolver_ipv6 = user_input.get(CONF_RESOLVER_IPV6, DEFAULT_RESOLVER_IPV6)
|
||||||
|
port_ipv6 = user_input.get(CONF_PORT_IPV6, DEFAULT_PORT)
|
||||||
validate = await async_validate_hostname(
|
validate = await async_validate_hostname(
|
||||||
self.config_entry.data[CONF_HOSTNAME],
|
self.config_entry.data[CONF_HOSTNAME],
|
||||||
resolver,
|
resolver,
|
||||||
resolver_ipv6,
|
resolver_ipv6,
|
||||||
|
port,
|
||||||
|
port_ipv6,
|
||||||
)
|
)
|
||||||
|
|
||||||
if (
|
if (
|
||||||
@ -178,7 +201,9 @@ class DnsIPOptionsFlowHandler(OptionsFlowWithConfigEntry):
|
|||||||
title=self.config_entry.title,
|
title=self.config_entry.title,
|
||||||
data={
|
data={
|
||||||
CONF_RESOLVER: resolver,
|
CONF_RESOLVER: resolver,
|
||||||
|
CONF_PORT: port,
|
||||||
CONF_RESOLVER_IPV6: resolver_ipv6,
|
CONF_RESOLVER_IPV6: resolver_ipv6,
|
||||||
|
CONF_PORT_IPV6: port_ipv6,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -186,7 +211,9 @@ class DnsIPOptionsFlowHandler(OptionsFlowWithConfigEntry):
|
|||||||
vol.Schema(
|
vol.Schema(
|
||||||
{
|
{
|
||||||
vol.Optional(CONF_RESOLVER): cv.string,
|
vol.Optional(CONF_RESOLVER): cv.string,
|
||||||
|
vol.Optional(CONF_PORT): cv.port,
|
||||||
vol.Optional(CONF_RESOLVER_IPV6): cv.string,
|
vol.Optional(CONF_RESOLVER_IPV6): cv.string,
|
||||||
|
vol.Optional(CONF_PORT_IPV6): cv.port,
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
self.config_entry.options,
|
self.config_entry.options,
|
||||||
|
@ -8,6 +8,7 @@ PLATFORMS = [Platform.SENSOR]
|
|||||||
CONF_HOSTNAME = "hostname"
|
CONF_HOSTNAME = "hostname"
|
||||||
CONF_RESOLVER = "resolver"
|
CONF_RESOLVER = "resolver"
|
||||||
CONF_RESOLVER_IPV6 = "resolver_ipv6"
|
CONF_RESOLVER_IPV6 = "resolver_ipv6"
|
||||||
|
CONF_PORT_IPV6 = "port_ipv6"
|
||||||
CONF_IPV4 = "ipv4"
|
CONF_IPV4 = "ipv4"
|
||||||
CONF_IPV6 = "ipv6"
|
CONF_IPV6 = "ipv6"
|
||||||
CONF_IPV6_V4 = "ipv6_v4"
|
CONF_IPV6_V4 = "ipv6_v4"
|
||||||
@ -16,4 +17,5 @@ DEFAULT_HOSTNAME = "myip.opendns.com"
|
|||||||
DEFAULT_IPV6 = False
|
DEFAULT_IPV6 = False
|
||||||
DEFAULT_NAME = "myip"
|
DEFAULT_NAME = "myip"
|
||||||
DEFAULT_RESOLVER = "208.67.222.222"
|
DEFAULT_RESOLVER = "208.67.222.222"
|
||||||
|
DEFAULT_PORT = 53
|
||||||
DEFAULT_RESOLVER_IPV6 = "2620:119:53::53"
|
DEFAULT_RESOLVER_IPV6 = "2620:119:53::53"
|
||||||
|
@ -11,7 +11,7 @@ from aiodns.error import DNSError
|
|||||||
|
|
||||||
from homeassistant.components.sensor import SensorEntity
|
from homeassistant.components.sensor import SensorEntity
|
||||||
from homeassistant.config_entries import ConfigEntry
|
from homeassistant.config_entries import ConfigEntry
|
||||||
from homeassistant.const import CONF_NAME
|
from homeassistant.const import CONF_NAME, CONF_PORT
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
from homeassistant.helpers.device_registry import DeviceEntryType, DeviceInfo
|
from homeassistant.helpers.device_registry import DeviceEntryType, DeviceInfo
|
||||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||||
@ -20,6 +20,7 @@ from .const import (
|
|||||||
CONF_HOSTNAME,
|
CONF_HOSTNAME,
|
||||||
CONF_IPV4,
|
CONF_IPV4,
|
||||||
CONF_IPV6,
|
CONF_IPV6,
|
||||||
|
CONF_PORT_IPV6,
|
||||||
CONF_RESOLVER,
|
CONF_RESOLVER,
|
||||||
CONF_RESOLVER_IPV6,
|
CONF_RESOLVER_IPV6,
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
@ -53,12 +54,14 @@ async def async_setup_entry(
|
|||||||
|
|
||||||
resolver_ipv4 = entry.options[CONF_RESOLVER]
|
resolver_ipv4 = entry.options[CONF_RESOLVER]
|
||||||
resolver_ipv6 = entry.options[CONF_RESOLVER_IPV6]
|
resolver_ipv6 = entry.options[CONF_RESOLVER_IPV6]
|
||||||
|
port_ipv4 = entry.options[CONF_PORT]
|
||||||
|
port_ipv6 = entry.options[CONF_PORT_IPV6]
|
||||||
|
|
||||||
entities = []
|
entities = []
|
||||||
if entry.data[CONF_IPV4]:
|
if entry.data[CONF_IPV4]:
|
||||||
entities.append(WanIpSensor(name, hostname, resolver_ipv4, False))
|
entities.append(WanIpSensor(name, hostname, resolver_ipv4, False, port_ipv4))
|
||||||
if entry.data[CONF_IPV6]:
|
if entry.data[CONF_IPV6]:
|
||||||
entities.append(WanIpSensor(name, hostname, resolver_ipv6, True))
|
entities.append(WanIpSensor(name, hostname, resolver_ipv6, True, port_ipv6))
|
||||||
|
|
||||||
async_add_entities(entities, update_before_add=True)
|
async_add_entities(entities, update_before_add=True)
|
||||||
|
|
||||||
@ -75,12 +78,13 @@ class WanIpSensor(SensorEntity):
|
|||||||
hostname: str,
|
hostname: str,
|
||||||
resolver: str,
|
resolver: str,
|
||||||
ipv6: bool,
|
ipv6: bool,
|
||||||
|
port: int,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Initialize the DNS IP sensor."""
|
"""Initialize the DNS IP sensor."""
|
||||||
self._attr_name = "IPv6" if ipv6 else None
|
self._attr_name = "IPv6" if ipv6 else None
|
||||||
self._attr_unique_id = f"{hostname}_{ipv6}"
|
self._attr_unique_id = f"{hostname}_{ipv6}"
|
||||||
self.hostname = hostname
|
self.hostname = hostname
|
||||||
self.resolver = aiodns.DNSResolver()
|
self.resolver = aiodns.DNSResolver(tcp_port=port, udp_port=port)
|
||||||
self.resolver.nameservers = [resolver]
|
self.resolver.nameservers = [resolver]
|
||||||
self.querytype = "AAAA" if ipv6 else "A"
|
self.querytype = "AAAA" if ipv6 else "A"
|
||||||
self._retries = DEFAULT_RETRIES
|
self._retries = DEFAULT_RETRIES
|
||||||
|
@ -5,7 +5,9 @@
|
|||||||
"data": {
|
"data": {
|
||||||
"hostname": "The hostname for which to perform the DNS query",
|
"hostname": "The hostname for which to perform the DNS query",
|
||||||
"resolver": "Resolver for IPV4 lookup",
|
"resolver": "Resolver for IPV4 lookup",
|
||||||
"resolver_ipv6": "Resolver for IPV6 lookup"
|
"port": "Port for IPV4 lookup",
|
||||||
|
"resolver_ipv6": "Resolver for IPV6 lookup",
|
||||||
|
"port_ipv6": "Port for IPV6 lookup"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -18,7 +20,9 @@
|
|||||||
"init": {
|
"init": {
|
||||||
"data": {
|
"data": {
|
||||||
"resolver": "[%key:component::dnsip::config::step::user::data::resolver%]",
|
"resolver": "[%key:component::dnsip::config::step::user::data::resolver%]",
|
||||||
"resolver_ipv6": "[%key:component::dnsip::config::step::user::data::resolver_ipv6%]"
|
"port": "[%key:component::dnsip::config::step::user::data::port%]",
|
||||||
|
"resolver_ipv6": "[%key:component::dnsip::config::step::user::data::resolver_ipv6%]",
|
||||||
|
"port_ipv6": "[%key:component::dnsip::config::step::user::data::port_ipv6%]"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -26,7 +30,7 @@
|
|||||||
"already_configured": "[%key:common::config_flow::abort::already_configured_service%]"
|
"already_configured": "[%key:common::config_flow::abort::already_configured_service%]"
|
||||||
},
|
},
|
||||||
"error": {
|
"error": {
|
||||||
"invalid_resolver": "Invalid IP address for resolver"
|
"invalid_resolver": "Invalid IP address or port for resolver"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,12 +13,13 @@ from homeassistant.components.dnsip.const import (
|
|||||||
CONF_HOSTNAME,
|
CONF_HOSTNAME,
|
||||||
CONF_IPV4,
|
CONF_IPV4,
|
||||||
CONF_IPV6,
|
CONF_IPV6,
|
||||||
|
CONF_PORT_IPV6,
|
||||||
CONF_RESOLVER,
|
CONF_RESOLVER,
|
||||||
CONF_RESOLVER_IPV6,
|
CONF_RESOLVER_IPV6,
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
)
|
)
|
||||||
from homeassistant.config_entries import ConfigEntryState
|
from homeassistant.config_entries import ConfigEntryState
|
||||||
from homeassistant.const import CONF_NAME
|
from homeassistant.const import CONF_NAME, CONF_PORT
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
from homeassistant.data_entry_flow import FlowResultType
|
from homeassistant.data_entry_flow import FlowResultType
|
||||||
|
|
||||||
@ -66,6 +67,8 @@ async def test_form(hass: HomeAssistant) -> None:
|
|||||||
assert result2["options"] == {
|
assert result2["options"] == {
|
||||||
"resolver": "208.67.222.222",
|
"resolver": "208.67.222.222",
|
||||||
"resolver_ipv6": "2620:119:53::53",
|
"resolver_ipv6": "2620:119:53::53",
|
||||||
|
"port": 53,
|
||||||
|
"port_ipv6": 53,
|
||||||
}
|
}
|
||||||
assert len(mock_setup_entry.mock_calls) == 1
|
assert len(mock_setup_entry.mock_calls) == 1
|
||||||
|
|
||||||
@ -96,6 +99,8 @@ async def test_form_adv(hass: HomeAssistant) -> None:
|
|||||||
CONF_HOSTNAME: "home-assistant.io",
|
CONF_HOSTNAME: "home-assistant.io",
|
||||||
CONF_RESOLVER: "8.8.8.8",
|
CONF_RESOLVER: "8.8.8.8",
|
||||||
CONF_RESOLVER_IPV6: "2620:119:53::53",
|
CONF_RESOLVER_IPV6: "2620:119:53::53",
|
||||||
|
CONF_PORT: 53,
|
||||||
|
CONF_PORT_IPV6: 53,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
@ -111,6 +116,8 @@ async def test_form_adv(hass: HomeAssistant) -> None:
|
|||||||
assert result2["options"] == {
|
assert result2["options"] == {
|
||||||
"resolver": "8.8.8.8",
|
"resolver": "8.8.8.8",
|
||||||
"resolver_ipv6": "2620:119:53::53",
|
"resolver_ipv6": "2620:119:53::53",
|
||||||
|
"port": 53,
|
||||||
|
"port_ipv6": 53,
|
||||||
}
|
}
|
||||||
assert len(mock_setup_entry.mock_calls) == 1
|
assert len(mock_setup_entry.mock_calls) == 1
|
||||||
|
|
||||||
@ -152,6 +159,8 @@ async def test_flow_already_exist(hass: HomeAssistant) -> None:
|
|||||||
options={
|
options={
|
||||||
CONF_RESOLVER: "208.67.222.222",
|
CONF_RESOLVER: "208.67.222.222",
|
||||||
CONF_RESOLVER_IPV6: "2620:119:53::5",
|
CONF_RESOLVER_IPV6: "2620:119:53::5",
|
||||||
|
CONF_PORT: 53,
|
||||||
|
CONF_PORT_IPV6: 53,
|
||||||
},
|
},
|
||||||
unique_id="home-assistant.io",
|
unique_id="home-assistant.io",
|
||||||
).add_to_hass(hass)
|
).add_to_hass(hass)
|
||||||
@ -197,6 +206,8 @@ async def test_options_flow(hass: HomeAssistant) -> None:
|
|||||||
options={
|
options={
|
||||||
CONF_RESOLVER: "208.67.222.222",
|
CONF_RESOLVER: "208.67.222.222",
|
||||||
CONF_RESOLVER_IPV6: "2620:119:53::5",
|
CONF_RESOLVER_IPV6: "2620:119:53::5",
|
||||||
|
CONF_PORT: 53,
|
||||||
|
CONF_PORT_IPV6: 53,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
entry.add_to_hass(hass)
|
entry.add_to_hass(hass)
|
||||||
@ -218,6 +229,8 @@ async def test_options_flow(hass: HomeAssistant) -> None:
|
|||||||
user_input={
|
user_input={
|
||||||
CONF_RESOLVER: "8.8.8.8",
|
CONF_RESOLVER: "8.8.8.8",
|
||||||
CONF_RESOLVER_IPV6: "2001:4860:4860::8888",
|
CONF_RESOLVER_IPV6: "2001:4860:4860::8888",
|
||||||
|
CONF_PORT: 53,
|
||||||
|
CONF_PORT_IPV6: 53,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
@ -226,6 +239,8 @@ async def test_options_flow(hass: HomeAssistant) -> None:
|
|||||||
assert result["data"] == {
|
assert result["data"] == {
|
||||||
"resolver": "8.8.8.8",
|
"resolver": "8.8.8.8",
|
||||||
"resolver_ipv6": "2001:4860:4860::8888",
|
"resolver_ipv6": "2001:4860:4860::8888",
|
||||||
|
"port": 53,
|
||||||
|
"port_ipv6": 53,
|
||||||
}
|
}
|
||||||
|
|
||||||
assert entry.state is ConfigEntryState.LOADED
|
assert entry.state is ConfigEntryState.LOADED
|
||||||
@ -245,6 +260,8 @@ async def test_options_flow_empty_return(hass: HomeAssistant) -> None:
|
|||||||
options={
|
options={
|
||||||
CONF_RESOLVER: "8.8.8.8",
|
CONF_RESOLVER: "8.8.8.8",
|
||||||
CONF_RESOLVER_IPV6: "2620:119:53::1",
|
CONF_RESOLVER_IPV6: "2620:119:53::1",
|
||||||
|
CONF_PORT: 53,
|
||||||
|
CONF_PORT_IPV6: 53,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
entry.add_to_hass(hass)
|
entry.add_to_hass(hass)
|
||||||
@ -271,6 +288,8 @@ async def test_options_flow_empty_return(hass: HomeAssistant) -> None:
|
|||||||
assert result["data"] == {
|
assert result["data"] == {
|
||||||
"resolver": "208.67.222.222",
|
"resolver": "208.67.222.222",
|
||||||
"resolver_ipv6": "2620:119:53::53",
|
"resolver_ipv6": "2620:119:53::53",
|
||||||
|
"port": 53,
|
||||||
|
"port_ipv6": 53,
|
||||||
}
|
}
|
||||||
|
|
||||||
entry = hass.config_entries.async_get_entry(entry.entry_id)
|
entry = hass.config_entries.async_get_entry(entry.entry_id)
|
||||||
@ -283,6 +302,8 @@ async def test_options_flow_empty_return(hass: HomeAssistant) -> None:
|
|||||||
assert entry.options == {
|
assert entry.options == {
|
||||||
"resolver": "208.67.222.222",
|
"resolver": "208.67.222.222",
|
||||||
"resolver_ipv6": "2620:119:53::53",
|
"resolver_ipv6": "2620:119:53::53",
|
||||||
|
"port": 53,
|
||||||
|
"port_ipv6": 53,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -294,6 +315,8 @@ async def test_options_flow_empty_return(hass: HomeAssistant) -> None:
|
|||||||
CONF_NAME: "home-assistant.io",
|
CONF_NAME: "home-assistant.io",
|
||||||
CONF_RESOLVER: "208.67.222.222",
|
CONF_RESOLVER: "208.67.222.222",
|
||||||
CONF_RESOLVER_IPV6: "2620:119:53::5",
|
CONF_RESOLVER_IPV6: "2620:119:53::5",
|
||||||
|
CONF_PORT: 53,
|
||||||
|
CONF_PORT_IPV6: 53,
|
||||||
CONF_IPV4: True,
|
CONF_IPV4: True,
|
||||||
CONF_IPV6: False,
|
CONF_IPV6: False,
|
||||||
},
|
},
|
||||||
@ -302,6 +325,8 @@ async def test_options_flow_empty_return(hass: HomeAssistant) -> None:
|
|||||||
CONF_NAME: "home-assistant.io",
|
CONF_NAME: "home-assistant.io",
|
||||||
CONF_RESOLVER: "208.67.222.222",
|
CONF_RESOLVER: "208.67.222.222",
|
||||||
CONF_RESOLVER_IPV6: "2620:119:53::5",
|
CONF_RESOLVER_IPV6: "2620:119:53::5",
|
||||||
|
CONF_PORT: 53,
|
||||||
|
CONF_PORT_IPV6: 53,
|
||||||
CONF_IPV4: False,
|
CONF_IPV4: False,
|
||||||
CONF_IPV6: True,
|
CONF_IPV6: True,
|
||||||
},
|
},
|
||||||
@ -334,6 +359,8 @@ async def test_options_error(hass: HomeAssistant, p_input: dict[str, str]) -> No
|
|||||||
{
|
{
|
||||||
CONF_RESOLVER: "192.168.200.34",
|
CONF_RESOLVER: "192.168.200.34",
|
||||||
CONF_RESOLVER_IPV6: "2001:4860:4860::8888",
|
CONF_RESOLVER_IPV6: "2001:4860:4860::8888",
|
||||||
|
CONF_PORT: 53,
|
||||||
|
CONF_PORT_IPV6: 53,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
@ -8,12 +8,14 @@ from homeassistant.components.dnsip.const import (
|
|||||||
CONF_HOSTNAME,
|
CONF_HOSTNAME,
|
||||||
CONF_IPV4,
|
CONF_IPV4,
|
||||||
CONF_IPV6,
|
CONF_IPV6,
|
||||||
|
CONF_PORT_IPV6,
|
||||||
CONF_RESOLVER,
|
CONF_RESOLVER,
|
||||||
CONF_RESOLVER_IPV6,
|
CONF_RESOLVER_IPV6,
|
||||||
|
DEFAULT_PORT,
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
)
|
)
|
||||||
from homeassistant.config_entries import SOURCE_USER, ConfigEntryState
|
from homeassistant.config_entries import SOURCE_USER, ConfigEntryState
|
||||||
from homeassistant.const import CONF_NAME
|
from homeassistant.const import CONF_NAME, CONF_PORT
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
|
|
||||||
from . import RetrieveDNS
|
from . import RetrieveDNS
|
||||||
@ -35,6 +37,8 @@ async def test_load_unload_entry(hass: HomeAssistant) -> None:
|
|||||||
options={
|
options={
|
||||||
CONF_RESOLVER: "208.67.222.222",
|
CONF_RESOLVER: "208.67.222.222",
|
||||||
CONF_RESOLVER_IPV6: "2620:119:53::53",
|
CONF_RESOLVER_IPV6: "2620:119:53::53",
|
||||||
|
CONF_PORT: 53,
|
||||||
|
CONF_PORT_IPV6: 53,
|
||||||
},
|
},
|
||||||
entry_id="1",
|
entry_id="1",
|
||||||
unique_id="home-assistant.io",
|
unique_id="home-assistant.io",
|
||||||
@ -52,3 +56,77 @@ async def test_load_unload_entry(hass: HomeAssistant) -> None:
|
|||||||
assert await hass.config_entries.async_unload(entry.entry_id)
|
assert await hass.config_entries.async_unload(entry.entry_id)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
assert entry.state is ConfigEntryState.NOT_LOADED
|
assert entry.state is ConfigEntryState.NOT_LOADED
|
||||||
|
|
||||||
|
|
||||||
|
async def test_port_migration(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
) -> None:
|
||||||
|
"""Test migration of the config entry from no ports to with ports."""
|
||||||
|
|
||||||
|
entry = MockConfigEntry(
|
||||||
|
domain=DOMAIN,
|
||||||
|
source=SOURCE_USER,
|
||||||
|
data={
|
||||||
|
CONF_HOSTNAME: "home-assistant.io",
|
||||||
|
CONF_NAME: "home-assistant.io",
|
||||||
|
CONF_IPV4: True,
|
||||||
|
CONF_IPV6: True,
|
||||||
|
},
|
||||||
|
options={
|
||||||
|
CONF_RESOLVER: "208.67.222.222",
|
||||||
|
CONF_RESOLVER_IPV6: "2620:119:53::53",
|
||||||
|
},
|
||||||
|
entry_id="1",
|
||||||
|
unique_id="home-assistant.io",
|
||||||
|
version=1,
|
||||||
|
minor_version=1,
|
||||||
|
)
|
||||||
|
entry.add_to_hass(hass)
|
||||||
|
|
||||||
|
with patch(
|
||||||
|
"homeassistant.components.dnsip.sensor.aiodns.DNSResolver",
|
||||||
|
return_value=RetrieveDNS(),
|
||||||
|
):
|
||||||
|
await hass.config_entries.async_setup(entry.entry_id)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
assert entry.version == 1
|
||||||
|
assert entry.minor_version == 2
|
||||||
|
assert entry.options[CONF_PORT] == DEFAULT_PORT
|
||||||
|
assert entry.options[CONF_PORT_IPV6] == DEFAULT_PORT
|
||||||
|
assert entry.state is ConfigEntryState.LOADED
|
||||||
|
|
||||||
|
|
||||||
|
async def test_migrate_error_from_future(hass: HomeAssistant) -> None:
|
||||||
|
"""Test a future version isn't migrated."""
|
||||||
|
|
||||||
|
entry = MockConfigEntry(
|
||||||
|
domain=DOMAIN,
|
||||||
|
source=SOURCE_USER,
|
||||||
|
data={
|
||||||
|
CONF_HOSTNAME: "home-assistant.io",
|
||||||
|
CONF_NAME: "home-assistant.io",
|
||||||
|
CONF_IPV4: True,
|
||||||
|
CONF_IPV6: True,
|
||||||
|
"some_new_data": "new_value",
|
||||||
|
},
|
||||||
|
options={
|
||||||
|
CONF_RESOLVER: "208.67.222.222",
|
||||||
|
CONF_RESOLVER_IPV6: "2620:119:53::53",
|
||||||
|
},
|
||||||
|
entry_id="1",
|
||||||
|
unique_id="home-assistant.io",
|
||||||
|
version=2,
|
||||||
|
minor_version=1,
|
||||||
|
)
|
||||||
|
entry.add_to_hass(hass)
|
||||||
|
|
||||||
|
with patch(
|
||||||
|
"homeassistant.components.dnsip.sensor.aiodns.DNSResolver",
|
||||||
|
return_value=RetrieveDNS(),
|
||||||
|
):
|
||||||
|
await hass.config_entries.async_setup(entry.entry_id)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
entry = hass.config_entries.async_get_entry(entry.entry_id)
|
||||||
|
assert entry.state is ConfigEntryState.MIGRATION_ERROR
|
||||||
|
@ -12,13 +12,14 @@ from homeassistant.components.dnsip.const import (
|
|||||||
CONF_HOSTNAME,
|
CONF_HOSTNAME,
|
||||||
CONF_IPV4,
|
CONF_IPV4,
|
||||||
CONF_IPV6,
|
CONF_IPV6,
|
||||||
|
CONF_PORT_IPV6,
|
||||||
CONF_RESOLVER,
|
CONF_RESOLVER,
|
||||||
CONF_RESOLVER_IPV6,
|
CONF_RESOLVER_IPV6,
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
)
|
)
|
||||||
from homeassistant.components.dnsip.sensor import SCAN_INTERVAL
|
from homeassistant.components.dnsip.sensor import SCAN_INTERVAL
|
||||||
from homeassistant.config_entries import SOURCE_USER
|
from homeassistant.config_entries import SOURCE_USER
|
||||||
from homeassistant.const import CONF_NAME, STATE_UNAVAILABLE
|
from homeassistant.const import CONF_NAME, CONF_PORT, STATE_UNAVAILABLE
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
|
|
||||||
from . import RetrieveDNS
|
from . import RetrieveDNS
|
||||||
@ -40,6 +41,8 @@ async def test_sensor(hass: HomeAssistant) -> None:
|
|||||||
options={
|
options={
|
||||||
CONF_RESOLVER: "208.67.222.222",
|
CONF_RESOLVER: "208.67.222.222",
|
||||||
CONF_RESOLVER_IPV6: "2620:119:53::53",
|
CONF_RESOLVER_IPV6: "2620:119:53::53",
|
||||||
|
CONF_PORT: 53,
|
||||||
|
CONF_PORT_IPV6: 53,
|
||||||
},
|
},
|
||||||
entry_id="1",
|
entry_id="1",
|
||||||
unique_id="home-assistant.io",
|
unique_id="home-assistant.io",
|
||||||
@ -67,6 +70,49 @@ async def test_sensor(hass: HomeAssistant) -> None:
|
|||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
async def test_legacy_sensor(hass: HomeAssistant) -> None:
|
||||||
|
"""Test the DNS IP sensor configured before the addition of ports."""
|
||||||
|
entry = MockConfigEntry(
|
||||||
|
domain=DOMAIN,
|
||||||
|
source=SOURCE_USER,
|
||||||
|
data={
|
||||||
|
CONF_HOSTNAME: "home-assistant.io",
|
||||||
|
CONF_NAME: "home-assistant.io",
|
||||||
|
CONF_IPV4: True,
|
||||||
|
CONF_IPV6: True,
|
||||||
|
},
|
||||||
|
options={
|
||||||
|
CONF_RESOLVER: "208.67.222.222",
|
||||||
|
CONF_RESOLVER_IPV6: "2620:119:53::53",
|
||||||
|
},
|
||||||
|
entry_id="1",
|
||||||
|
unique_id="home-assistant.io",
|
||||||
|
version=1,
|
||||||
|
minor_version=1,
|
||||||
|
)
|
||||||
|
entry.add_to_hass(hass)
|
||||||
|
|
||||||
|
with patch(
|
||||||
|
"homeassistant.components.dnsip.sensor.aiodns.DNSResolver",
|
||||||
|
return_value=RetrieveDNS(),
|
||||||
|
):
|
||||||
|
await hass.config_entries.async_setup(entry.entry_id)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
state1 = hass.states.get("sensor.home_assistant_io")
|
||||||
|
state2 = hass.states.get("sensor.home_assistant_io_ipv6")
|
||||||
|
|
||||||
|
assert state1.state == "1.1.1.1"
|
||||||
|
assert state1.attributes["ip_addresses"] == ["1.1.1.1", "1.2.3.4"]
|
||||||
|
assert state2.state == "2001:db8::77:dead:beef"
|
||||||
|
assert state2.attributes["ip_addresses"] == [
|
||||||
|
"2001:db8::77:dead:beef",
|
||||||
|
"2001:db8:66::dead:beef",
|
||||||
|
"2001:db8:77::dead:beef",
|
||||||
|
"2001:db8:77::face:b00c",
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
async def test_sensor_no_response(
|
async def test_sensor_no_response(
|
||||||
hass: HomeAssistant, freezer: FrozenDateTimeFactory
|
hass: HomeAssistant, freezer: FrozenDateTimeFactory
|
||||||
) -> None:
|
) -> None:
|
||||||
@ -83,6 +129,8 @@ async def test_sensor_no_response(
|
|||||||
options={
|
options={
|
||||||
CONF_RESOLVER: "208.67.222.222",
|
CONF_RESOLVER: "208.67.222.222",
|
||||||
CONF_RESOLVER_IPV6: "2620:119:53::53",
|
CONF_RESOLVER_IPV6: "2620:119:53::53",
|
||||||
|
CONF_PORT: 53,
|
||||||
|
CONF_PORT_IPV6: 53,
|
||||||
},
|
},
|
||||||
entry_id="1",
|
entry_id="1",
|
||||||
unique_id="home-assistant.io",
|
unique_id="home-assistant.io",
|
||||||
|
Loading…
x
Reference in New Issue
Block a user