Remove embedded MQTT broker (#37032)
This commit is contained in:
parent
a004e6aa68
commit
1b3e5460a9
7 changed files with 3 additions and 265 deletions
|
@ -42,7 +42,7 @@ from homeassistant.util.logging import catch_log_exception
|
|||
|
||||
# Loading the config flow file will register the flow
|
||||
from . import config_flow # noqa: F401 pylint: disable=unused-import
|
||||
from . import debug_info, discovery, server
|
||||
from . import debug_info, discovery
|
||||
from .const import (
|
||||
ATTR_DISCOVERY_HASH,
|
||||
ATTR_DISCOVERY_TOPIC,
|
||||
|
@ -80,8 +80,6 @@ DATA_MQTT_CONFIG = "mqtt_config"
|
|||
SERVICE_PUBLISH = "publish"
|
||||
SERVICE_DUMP = "dump"
|
||||
|
||||
CONF_EMBEDDED = "embedded"
|
||||
|
||||
CONF_DISCOVERY_PREFIX = "discovery_prefix"
|
||||
CONF_KEEPALIVE = "keepalive"
|
||||
CONF_CERTIFICATE = "certificate"
|
||||
|
@ -169,7 +167,7 @@ CONFIG_SCHEMA = vol.Schema(
|
|||
vol.Optional(CONF_KEEPALIVE, default=DEFAULT_KEEPALIVE): vol.All(
|
||||
vol.Coerce(int), vol.Range(min=15)
|
||||
),
|
||||
vol.Optional(CONF_BROKER): cv.string,
|
||||
vol.Required(CONF_BROKER): cv.string,
|
||||
vol.Optional(CONF_PORT, default=DEFAULT_PORT): cv.port,
|
||||
vol.Optional(CONF_USERNAME): cv.string,
|
||||
vol.Optional(CONF_PASSWORD): cv.string,
|
||||
|
@ -187,9 +185,6 @@ CONFIG_SCHEMA = vol.Schema(
|
|||
vol.Optional(CONF_PROTOCOL, default=DEFAULT_PROTOCOL): vol.All(
|
||||
cv.string, vol.In([PROTOCOL_31, PROTOCOL_311])
|
||||
),
|
||||
vol.Optional(CONF_EMBEDDED): vol.All(
|
||||
server.HBMQTT_CONFIG_SCHEMA, embedded_broker_deprecated
|
||||
),
|
||||
vol.Optional(CONF_WILL_MESSAGE): MQTT_WILL_BIRTH_SCHEMA,
|
||||
vol.Optional(CONF_BIRTH_MESSAGE): MQTT_WILL_BIRTH_SCHEMA,
|
||||
vol.Optional(CONF_DISCOVERY, default=DEFAULT_DISCOVERY): cv.boolean,
|
||||
|
@ -418,23 +413,6 @@ def subscribe(
|
|||
return remove
|
||||
|
||||
|
||||
async def _async_setup_server(hass: HomeAssistantType, config: ConfigType):
|
||||
"""Try to start embedded MQTT broker.
|
||||
|
||||
This method is a coroutine.
|
||||
"""
|
||||
conf: ConfigType = config.get(DOMAIN, {})
|
||||
|
||||
success, broker_config = await server.async_start(
|
||||
hass, conf.get(CONF_PASSWORD), conf.get(CONF_EMBEDDED)
|
||||
)
|
||||
|
||||
if not success:
|
||||
return None
|
||||
|
||||
return broker_config
|
||||
|
||||
|
||||
async def _async_setup_discovery(
|
||||
hass: HomeAssistantType, conf: ConfigType, config_entry
|
||||
) -> bool:
|
||||
|
@ -464,28 +442,6 @@ async def async_setup(hass: HomeAssistantType, config: ConfigType) -> bool:
|
|||
|
||||
conf = dict(conf)
|
||||
|
||||
if CONF_EMBEDDED in conf or CONF_BROKER not in conf:
|
||||
|
||||
broker_config = await _async_setup_server(hass, config)
|
||||
|
||||
if broker_config is None:
|
||||
_LOGGER.error("Unable to start embedded MQTT broker")
|
||||
return False
|
||||
|
||||
conf.update(
|
||||
{
|
||||
CONF_BROKER: broker_config[0],
|
||||
CONF_PORT: broker_config[1],
|
||||
CONF_USERNAME: broker_config[2],
|
||||
CONF_PASSWORD: broker_config[3],
|
||||
CONF_CERTIFICATE: broker_config[4],
|
||||
CONF_PROTOCOL: broker_config[5],
|
||||
CONF_CLIENT_KEY: None,
|
||||
CONF_CLIENT_CERT: None,
|
||||
CONF_TLS_INSECURE: None,
|
||||
}
|
||||
)
|
||||
|
||||
hass.data[DATA_MQTT_CONFIG] = conf
|
||||
|
||||
# Only import if we haven't before.
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
"name": "MQTT",
|
||||
"config_flow": true,
|
||||
"documentation": "https://www.home-assistant.io/integrations/mqtt",
|
||||
"requirements": ["hbmqtt==0.9.5", "paho-mqtt==1.5.0"],
|
||||
"requirements": ["paho-mqtt==1.5.0"],
|
||||
"dependencies": ["http"],
|
||||
"codeowners": ["@home-assistant/core", "@emontnemery"]
|
||||
}
|
||||
|
|
|
@ -1,99 +0,0 @@
|
|||
"""Support for a local MQTT broker."""
|
||||
import logging
|
||||
import tempfile
|
||||
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.const import EVENT_HOMEASSISTANT_STOP
|
||||
import homeassistant.helpers.config_validation as cv
|
||||
|
||||
from .const import PROTOCOL_311
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
# None allows custom config to be created through generate_config
|
||||
HBMQTT_CONFIG_SCHEMA = vol.Any(
|
||||
None,
|
||||
vol.Schema(
|
||||
{
|
||||
vol.Optional("auth"): vol.Schema(
|
||||
{vol.Optional("password-file"): cv.isfile}, extra=vol.ALLOW_EXTRA
|
||||
),
|
||||
vol.Optional("listeners"): vol.Schema(
|
||||
{vol.Required("default"): vol.Schema(dict), str: vol.Schema(dict)}
|
||||
),
|
||||
},
|
||||
extra=vol.ALLOW_EXTRA,
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
async def async_start(hass, password, server_config):
|
||||
"""Initialize MQTT Server.
|
||||
|
||||
This method is a coroutine.
|
||||
"""
|
||||
# pylint: disable=import-outside-toplevel
|
||||
from hbmqtt.broker import Broker, BrokerException
|
||||
|
||||
passwd = tempfile.NamedTemporaryFile()
|
||||
|
||||
gen_server_config, client_config = generate_config(hass, passwd, password)
|
||||
|
||||
try:
|
||||
if server_config is None:
|
||||
server_config = gen_server_config
|
||||
|
||||
broker = Broker(server_config, hass.loop)
|
||||
await broker.start()
|
||||
except BrokerException:
|
||||
_LOGGER.exception("Error initializing MQTT server")
|
||||
return False, None
|
||||
finally:
|
||||
passwd.close()
|
||||
|
||||
async def async_shutdown_mqtt_server(event):
|
||||
"""Shut down the MQTT server."""
|
||||
await broker.shutdown()
|
||||
|
||||
hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP, async_shutdown_mqtt_server)
|
||||
|
||||
return True, client_config
|
||||
|
||||
|
||||
def generate_config(hass, passwd, password):
|
||||
"""Generate a configuration based on current Home Assistant instance."""
|
||||
# pylint: disable=import-outside-toplevel
|
||||
from passlib.apps import custom_app_context
|
||||
|
||||
config = {
|
||||
"listeners": {
|
||||
"default": {
|
||||
"max-connections": 50000,
|
||||
"bind": "0.0.0.0:1883",
|
||||
"type": "tcp",
|
||||
},
|
||||
"ws-1": {"bind": "0.0.0.0:8080", "type": "ws"},
|
||||
},
|
||||
"auth": {"allow-anonymous": password is None},
|
||||
"plugins": ["auth_anonymous"],
|
||||
"topic-check": {"enabled": True, "plugins": ["topic_taboo"]},
|
||||
}
|
||||
|
||||
if password:
|
||||
username = "homeassistant"
|
||||
|
||||
# Encrypt with what hbmqtt uses to verify
|
||||
passwd.write(
|
||||
f"homeassistant:{custom_app_context.encrypt(password)}\n".encode("utf-8")
|
||||
)
|
||||
passwd.flush()
|
||||
|
||||
config["auth"]["password-file"] = passwd.name
|
||||
config["plugins"].append("auth_file")
|
||||
else:
|
||||
username = None
|
||||
|
||||
client_config = ("localhost", 1883, username, password, None, PROTOCOL_311)
|
||||
|
||||
return config, client_config
|
|
@ -713,9 +713,6 @@ hangups==0.4.9
|
|||
# homeassistant.components.cloud
|
||||
hass-nabucasa==0.34.7
|
||||
|
||||
# homeassistant.components.mqtt
|
||||
hbmqtt==0.9.5
|
||||
|
||||
# homeassistant.components.jewish_calendar
|
||||
hdate==0.9.5
|
||||
|
||||
|
|
|
@ -324,9 +324,6 @@ hangups==0.4.9
|
|||
# homeassistant.components.cloud
|
||||
hass-nabucasa==0.34.7
|
||||
|
||||
# homeassistant.components.mqtt
|
||||
hbmqtt==0.9.5
|
||||
|
||||
# homeassistant.components.jewish_calendar
|
||||
hdate==0.9.5
|
||||
|
||||
|
|
|
@ -670,32 +670,6 @@ async def test_restore_all_active_subscriptions_on_reconnect(
|
|||
assert mqtt_client_mock.subscribe.mock_calls == expected
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def mqtt_server_start_mock(hass):
|
||||
"""Mock embedded server start."""
|
||||
client_config = ("localhost", 1883, "user", "pass", None, "3.1.1")
|
||||
|
||||
with patch(
|
||||
"homeassistant.components.mqtt.server.async_start",
|
||||
return_value=(True, client_config),
|
||||
) as _start:
|
||||
yield _start
|
||||
|
||||
|
||||
@pytest.mark.parametrize("mqtt_config", [{}])
|
||||
async def test_setup_embedded_starts_with_no_config(
|
||||
hass, mqtt_server_start_mock, mqtt_mock
|
||||
):
|
||||
"""Test setting up embedded server with no config."""
|
||||
assert mqtt_server_start_mock.call_count == 1
|
||||
|
||||
|
||||
@pytest.mark.parametrize("mqtt_config", [{"embedded": None}])
|
||||
async def test_setup_embedded_with_embedded(hass, mqtt_server_start_mock, mqtt_mock):
|
||||
"""Test setting up embedded server with empty embedded config."""
|
||||
assert mqtt_server_start_mock.call_count == 1
|
||||
|
||||
|
||||
async def test_setup_logs_error_if_no_connect_broker(hass, caplog):
|
||||
"""Test for setup failure if connection to broker is missing."""
|
||||
entry = MockConfigEntry(domain=mqtt.DOMAIN, data={mqtt.CONF_BROKER: "test-broker"})
|
||||
|
|
|
@ -1,87 +0,0 @@
|
|||
"""The tests for the MQTT component embedded server."""
|
||||
from unittest.mock import MagicMock, Mock
|
||||
|
||||
import pytest
|
||||
|
||||
import homeassistant.components.mqtt as mqtt
|
||||
from homeassistant.const import CONF_PASSWORD
|
||||
from homeassistant.setup import setup_component
|
||||
|
||||
from tests.async_mock import AsyncMock, patch
|
||||
from tests.common import get_test_home_assistant, mock_coro
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def inject_fixture(hass_storage):
|
||||
"""Inject pytest fixtures."""
|
||||
|
||||
|
||||
class TestMQTT:
|
||||
"""Test the MQTT component."""
|
||||
|
||||
def setup_method(self, method):
|
||||
"""Set up things to be run when tests are started."""
|
||||
self.hass = get_test_home_assistant()
|
||||
|
||||
def teardown_method(self, method):
|
||||
"""Stop everything that was started."""
|
||||
self.hass.stop()
|
||||
|
||||
@patch("passlib.apps.custom_app_context", Mock(return_value=""))
|
||||
@patch("tempfile.NamedTemporaryFile", Mock(return_value=MagicMock()))
|
||||
@patch("hbmqtt.broker.Broker", Mock(return_value=MagicMock(start=AsyncMock())))
|
||||
@patch("hbmqtt.broker.Broker.start", AsyncMock(return_value=None))
|
||||
@patch("homeassistant.components.mqtt.MQTT")
|
||||
def test_creating_config_with_pass_and_no_http_pass(self, mock_mqtt):
|
||||
"""Test if the MQTT server gets started with password.
|
||||
|
||||
Since 0.77, MQTT server has to set up its own password.
|
||||
"""
|
||||
mock_mqtt().async_connect = AsyncMock(return_value=True)
|
||||
self.hass.bus.listen_once = MagicMock()
|
||||
password = "mqtt_secret"
|
||||
|
||||
assert setup_component(
|
||||
self.hass, mqtt.DOMAIN, {mqtt.DOMAIN: {CONF_PASSWORD: password}}
|
||||
)
|
||||
self.hass.block_till_done()
|
||||
assert mock_mqtt.called
|
||||
assert mock_mqtt.mock_calls[1][1][2]["username"] == "homeassistant"
|
||||
assert mock_mqtt.mock_calls[1][1][2]["password"] == password
|
||||
|
||||
@patch("passlib.apps.custom_app_context", Mock(return_value=""))
|
||||
@patch("tempfile.NamedTemporaryFile", Mock(return_value=MagicMock()))
|
||||
@patch("hbmqtt.broker.Broker", Mock(return_value=MagicMock(start=AsyncMock())))
|
||||
@patch("hbmqtt.broker.Broker.start", AsyncMock(return_value=None))
|
||||
@patch("homeassistant.components.mqtt.MQTT")
|
||||
def test_creating_config_with_pass_and_http_pass(self, mock_mqtt):
|
||||
"""Test if the MQTT server gets started with password.
|
||||
|
||||
Since 0.77, MQTT server has to set up its own password.
|
||||
"""
|
||||
mock_mqtt().async_connect = AsyncMock(return_value=True)
|
||||
self.hass.bus.listen_once = MagicMock()
|
||||
password = "mqtt_secret"
|
||||
|
||||
self.hass.config.api = MagicMock(api_password="api_password")
|
||||
assert setup_component(
|
||||
self.hass, mqtt.DOMAIN, {mqtt.DOMAIN: {CONF_PASSWORD: password}}
|
||||
)
|
||||
self.hass.block_till_done()
|
||||
assert mock_mqtt.called
|
||||
assert mock_mqtt.mock_calls[1][1][2]["username"] == "homeassistant"
|
||||
assert mock_mqtt.mock_calls[1][1][2]["password"] == password
|
||||
|
||||
@patch("tempfile.NamedTemporaryFile", Mock(return_value=MagicMock()))
|
||||
@patch("hbmqtt.broker.Broker.start", return_value=mock_coro())
|
||||
def test_broker_config_fails(self, mock_run):
|
||||
"""Test if the MQTT component fails if server fails."""
|
||||
from hbmqtt.broker import BrokerException
|
||||
|
||||
mock_run.side_effect = BrokerException
|
||||
|
||||
self.hass.config.api = MagicMock(api_password=None)
|
||||
|
||||
assert not setup_component(
|
||||
self.hass, mqtt.DOMAIN, {mqtt.DOMAIN: {mqtt.CONF_EMBEDDED: {}}}
|
||||
)
|
Loading…
Add table
Reference in a new issue