Skip to content

[bug] SSH exec_command throws away partial output and leaks channel on timeout #1424

Description

@asmodehn

Describe the bug

When exec_command hits its SSH command timeout, any output the remote process sent before the timeout is silently discarded. The channel also remains open on the server side.

Three separate problems at openwisp_controller/connection/connectors/ssh.py:

  1. Partial output lost (lines 205-210). After status_event.wait() returns False, the method raises CommandTimeoutException without ever reading stdout or stderr:

    if not stdout.channel.status_event.wait(timeout=...):
        log_message = f"Command timed out after {timeout} seconds."
        logger.info(log_message)
        raise CommandTimeoutException(log_message)
  2. Channel leak (same block). No channel.close() is called, so the server-side session for the timed-out command is never released until the SSH transport is torn down.

  3. Traceback lost (lines 196-197). except socket.timeout: raise socket.timeout() creates a new exception instead of using bare raise, discarding the original traceback.
    => Not sure if this is intended or not ? if so I would add a comment next to it...

Steps To Reproduce

  1. Set up an SSH device connection with a remote host.
  2. Call connector_instance.exec_command("echo partial_output && sleep 60", timeout=0.5).
  3. Observe that CommandTimeoutException is raised with no .output attribute — "partial_output" is lost.
  4. Similar concerns for stderr...

Expected behavior

  • If the remote process managed to produce any output before the timeout, that output should be available to the caller (e.g., as the message or an attribute of the exception).
  • The SSH channel used for the timed-out command should be closed so the server can reclaim resources.
  • The original traceback should likely be preserved when socket.timeout propagates.

System Information:

  • OS: any
  • Python Version: any (3.x)
  • OpenWISP Controller version: master (v1.2.x)

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions