Skip to content

Commit 53bf4f0

Browse files
author
Alexandre Vincent
committed
[change] CommandTimeoutException on ssh command timeout
1 parent 4bab0ce commit 53bf4f0

File tree

4 files changed

+28
-13
lines changed

4 files changed

+28
-13
lines changed

openwisp_controller/connection/connectors/exceptions.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,11 @@ class CommandFailedException(Exception):
44
"""
55

66
pass
7+
8+
9+
class CommandTimeoutException(Exception):
10+
"""
11+
raised when a command times out
12+
"""
13+
14+
pass

openwisp_controller/connection/connectors/ssh.py

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
from scp import SCPClient
1212

1313
from .. import settings as app_settings
14-
from .exceptions import CommandFailedException
14+
from .exceptions import CommandFailedException, CommandTimeoutException
1515

1616
logger = logging.getLogger(__name__)
1717

@@ -184,6 +184,9 @@ def exec_command(
184184
- aborts on exceptions
185185
- raises socket.timeout exceptions
186186
"""
187+
# paramiko expects timeout as a float
188+
timeout = float(timeout)
189+
187190
logger.info("Executing command: {0}".format(command))
188191
# execute commmand
189192
try:
@@ -197,17 +200,16 @@ def exec_command(
197200
except Exception as e:
198201
logger.exception(e)
199202
raise e
200-
# store command exit status
201-
exit_status = None
203+
202204
# workaround https://github.com/paramiko/paramiko/issues/1815
203205
# workaround https://github.com/paramiko/paramiko/issues/1787
204206
# Ref. https://docs.paramiko.org/en/stable/api/channel.html#paramiko.channel.Channel.recv_exit_status # noqa
205207
if not stdout.channel.status_event.wait(
206-
timeout=timeout - int(time.perf_counter() - start_cmd)
208+
timeout=timeout - (time.perf_counter() - start_cmd)
207209
):
208-
output = "Command timeout exceeded."
209-
logger.info(output)
210-
return output, -1
210+
log_message = "Command timeout exceeded."
211+
logger.info(log_message)
212+
raise CommandTimeoutException(log_message)
211213

212214
exit_status = stdout.channel.exit_status
213215
# log standard output

openwisp_controller/connection/tasks.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
from swapper import load_model
1010

1111
from . import settings as app_settings
12+
from .connectors.exceptions import CommandTimeoutException
1213
from .exceptions import NoWorkingDeviceConnectionError
1314

1415
logger = logging.getLogger(__name__)
@@ -76,6 +77,10 @@ def launch_command(command_id):
7677
command.status = "failed"
7778
command._add_output(_("Background task time limit exceeded."))
7879
command.save()
80+
except CommandTimeoutException as e:
81+
command.status = "failed"
82+
command._add_output(_(f"{e}"))
83+
command.save()
7984
except Exception as e:
8085
logger.exception(
8186
f"An exception was raised while executing command {command_id}"

openwisp_controller/connection/tests/test_ssh.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -76,12 +76,12 @@ def test_connection_command_timeout(self, mocked_debug, mocked_info):
7676
ckey = self._create_credentials_with_key(port=self.ssh_server.port)
7777
dc = self._create_device_connection(credentials=ckey)
7878
dc.connector_instance.connect()
79-
dc.connector_instance.exec_command("sleep 1", timeout=0)
80-
mocked_info.assert_has_calls(
81-
[
82-
mock.call("Command timeout exceeded."),
83-
]
84-
)
79+
with self.assertRaises(Exception) as ctx:
80+
# timeout of 0.0 is a special case in paramiko -> we check for 0.01 instead
81+
dc.connector_instance.exec_command("sleep 1", timeout=0.01)
82+
log_message = "Command timeout exceeded."
83+
mocked_info.assert_has_calls([mock.call(log_message)])
84+
self.assertEqual(str(ctx.exception), log_message)
8585

8686
@mock.patch.object(ssh_logger, "info")
8787
@mock.patch.object(ssh_logger, "debug")

0 commit comments

Comments
 (0)