Report error code in log when command fails (#74319)

This commit is contained in:
atlflyer 2022-07-02 09:58:08 -04:00 committed by GitHub
parent 255c3c5b9a
commit da11cef29a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 59 additions and 7 deletions

View File

@ -23,7 +23,11 @@ def call_shell_with_timeout(
return 0 return 0
except subprocess.CalledProcessError as proc_exception: except subprocess.CalledProcessError as proc_exception:
if log_return_code: if log_return_code:
_LOGGER.error("Command failed: %s", command) _LOGGER.error(
"Command failed (with return code %s): %s",
proc_exception.returncode,
command,
)
return proc_exception.returncode return proc_exception.returncode
except subprocess.TimeoutExpired: except subprocess.TimeoutExpired:
_LOGGER.error("Timeout for command: %s", command) _LOGGER.error("Timeout for command: %s", command)
@ -40,8 +44,10 @@ def check_output_or_log(command: str, timeout: int) -> str | None:
command, shell=True, timeout=timeout # nosec # shell by design command, shell=True, timeout=timeout # nosec # shell by design
) )
return return_value.strip().decode("utf-8") return return_value.strip().decode("utf-8")
except subprocess.CalledProcessError: except subprocess.CalledProcessError as err:
_LOGGER.error("Command failed: %s", command) _LOGGER.error(
"Command failed (with return code %s): %s", err.returncode, command
)
except subprocess.TimeoutExpired: except subprocess.TimeoutExpired:
_LOGGER.error("Timeout for command: %s", command) _LOGGER.error("Timeout for command: %s", command)
except subprocess.SubprocessError: except subprocess.SubprocessError:

View File

@ -115,10 +115,13 @@ class CommandCover(CoverEntity):
"""Execute the actual commands.""" """Execute the actual commands."""
_LOGGER.info("Running command: %s", command) _LOGGER.info("Running command: %s", command)
success = call_shell_with_timeout(command, self._timeout) == 0 returncode = call_shell_with_timeout(command, self._timeout)
success = returncode == 0
if not success: if not success:
_LOGGER.error("Command failed: %s", command) _LOGGER.error(
"Command failed (with return code %s): %s", returncode, command
)
return success return success

View File

@ -57,7 +57,11 @@ class CommandLineNotificationService(BaseNotificationService):
try: try:
proc.communicate(input=message, timeout=self._timeout) proc.communicate(input=message, timeout=self._timeout)
if proc.returncode != 0: if proc.returncode != 0:
_LOGGER.error("Command failed: %s", self.command) _LOGGER.error(
"Command failed (with return code %s): %s",
proc.returncode,
self.command,
)
except subprocess.TimeoutExpired: except subprocess.TimeoutExpired:
_LOGGER.error("Timeout for command: %s", self.command) _LOGGER.error("Timeout for command: %s", self.command)
kill_subprocess(proc) kill_subprocess(proc)

View File

@ -3,6 +3,8 @@ from __future__ import annotations
from typing import Any from typing import Any
from pytest import LogCaptureFixture
from homeassistant import setup from homeassistant import setup
from homeassistant.components.binary_sensor import DOMAIN from homeassistant.components.binary_sensor import DOMAIN
from homeassistant.const import STATE_OFF, STATE_ON from homeassistant.const import STATE_OFF, STATE_ON
@ -112,3 +114,14 @@ async def test_unique_id(hass: HomeAssistant) -> None:
) )
is not None is not None
) )
async def test_return_code(caplog: LogCaptureFixture, hass: HomeAssistant) -> None:
"""Test setting the state with a template."""
await setup_test_entity(
hass,
{
"command": "exit 33",
},
)
assert "return code 33" in caplog.text

View File

@ -155,7 +155,7 @@ async def test_reload(hass: HomeAssistant) -> None:
async def test_move_cover_failure( async def test_move_cover_failure(
caplog: LogCaptureFixture, hass: HomeAssistant caplog: LogCaptureFixture, hass: HomeAssistant
) -> None: ) -> None:
"""Test with state value.""" """Test command failure."""
await setup_test_entity( await setup_test_entity(
hass, hass,
@ -165,6 +165,7 @@ async def test_move_cover_failure(
DOMAIN, SERVICE_OPEN_COVER, {ATTR_ENTITY_ID: "cover.test"}, blocking=True DOMAIN, SERVICE_OPEN_COVER, {ATTR_ENTITY_ID: "cover.test"}, blocking=True
) )
assert "Command failed" in caplog.text assert "Command failed" in caplog.text
assert "return code 1" in caplog.text
async def test_unique_id(hass: HomeAssistant) -> None: async def test_unique_id(hass: HomeAssistant) -> None:

View File

@ -77,6 +77,7 @@ async def test_error_for_none_zero_exit_code(
DOMAIN, "test", {"message": "error"}, blocking=True DOMAIN, "test", {"message": "error"}, blocking=True
) )
assert "Command failed" in caplog.text assert "Command failed" in caplog.text
assert "return code 1" in caplog.text
async def test_timeout(caplog: LogCaptureFixture, hass: HomeAssistant) -> None: async def test_timeout(caplog: LogCaptureFixture, hass: HomeAssistant) -> None:

View File

@ -128,6 +128,17 @@ async def test_bad_command(hass: HomeAssistant) -> None:
assert entity_state.state == "unknown" assert entity_state.state == "unknown"
async def test_return_code(caplog: LogCaptureFixture, hass: HomeAssistant) -> None:
"""Test that an error return code is logged."""
await setup_test_entities(
hass,
{
"command": "exit 33",
},
)
assert "return code 33" in caplog.text
async def test_update_with_json_attrs(hass: HomeAssistant) -> None: async def test_update_with_json_attrs(hass: HomeAssistant) -> None:
"""Test attributes get extracted from a JSON result.""" """Test attributes get extracted from a JSON result."""
await setup_test_entities( await setup_test_entities(

View File

@ -419,3 +419,16 @@ async def test_unique_id(hass: HomeAssistant) -> None:
ent_reg.async_get_entity_id("switch", "command_line", "not-so-unique-anymore") ent_reg.async_get_entity_id("switch", "command_line", "not-so-unique-anymore")
is not None is not None
) )
async def test_command_failure(caplog: LogCaptureFixture, hass: HomeAssistant) -> None:
"""Test command failure."""
await setup_test_entity(
hass,
{"test": {"command_off": "exit 33"}},
)
await hass.services.async_call(
DOMAIN, SERVICE_TURN_OFF, {ATTR_ENTITY_ID: "switch.test"}, blocking=True
)
assert "return code 33" in caplog.text