Skip to content

Commit

Permalink
Fix bug with pty argument to open a single use exec command channel.
Browse files Browse the repository at this point in the history
Add test for `redssh.RedSSH().execute_command()`.
Version bump.
  • Loading branch information
Red-M committed Feb 22, 2023
1 parent f8f9728 commit fc789cf
Show file tree
Hide file tree
Showing 5 changed files with 36 additions and 9 deletions.
2 changes: 1 addition & 1 deletion redssh/__init__.py
Expand Up @@ -23,7 +23,7 @@
'''
VERSION = u'3.0.0'
VERSION = u'3.0.1'

from .redssh import RedSSH
from . import clients
Expand Down
10 changes: 7 additions & 3 deletions redssh/clients/libssh/redsshlibssh.py
Expand Up @@ -324,7 +324,7 @@ def connect(self,hostname,port=22,username='',password=None,
# self._ssh_keepalive_event = threading.Event()
# self._ssh_keepalive_thread.start()
self.session.set_blocking(False)
self.channel = self.open_channel(True,True)
self.channel = self.open_channel(True,self.request_pty)

# if 'callback_set' in dir(self.session):
# self._forward_x11()
Expand Down Expand Up @@ -378,14 +378,18 @@ def last_error(self):
'''
return(self._block(self.session.get_error))

def execute_command(self,command,env=None,channel=None):
def execute_command(self,command,env=None,channel=None,pty=False):
'''
Run a command. This will block as the command executes.
:param command: Command to execute.
:type command: ``str``
:param env: Environment variables to set during ``command``.
:type env: ``dict``
:param channel: Use an existing SSH channel instead of spawning a new one.
:type channel: ``redssh.RedSSH.channel``
:param pty: Request a pty for the command to be executed via.
:type pty: ``bool``
:return: ``tuple (int, str)`` - of ``(return_code, command_output)``
'''
if env==None:
Expand All @@ -395,7 +399,7 @@ def execute_command(self,command,env=None,channel=None):
self.setenv(key,env[key])
out = b''
if channel==None:
channel = self.open_channel(True,True)
channel = self.open_channel(True,pty)
self._block(channel.request_exec,command)
ret = self._block(channel.get_exit_status)
while self._block(channel.is_eof)==False and ret==-1:
Expand Down
9 changes: 7 additions & 2 deletions redssh/clients/libssh2/redsshlibssh2.py
Expand Up @@ -337,7 +337,7 @@ def connect(self,hostname,port=22,username='',password=None,
self._ssh_keepalive_thread = threading.Thread(target=self.ssh_keepalive)
self._ssh_keepalive_event = threading.Event()
self._ssh_keepalive_thread.start()
self.channel = self.open_channel(True,True)
self.channel = self.open_channel(True,self.request_pty)

# if 'callback_set' in dir(self.session):
# self._forward_x11()
Expand Down Expand Up @@ -393,14 +393,18 @@ def last_error(self):
'''
return(self._block(self.session.last_error))

def execute_command(self,command,env=None,channel=None):
def execute_command(self,command,env=None,channel=None,pty=False):
'''
Run a command. This will block as the command executes.
:param command: Command to execute.
:type command: ``str``
:param env: Environment variables to set during ``command``.
:type env: ``dict``
:param channel: Use an existing SSH channel instead of spawning a new one.
:type channel: ``redssh.RedSSH.channel``
:param pty: Request a pty for the command to be executed via.
:type pty: ``bool``
:return: ``tuple (int, str)`` - of ``(return_code, command_output)``
'''
if env==None:
Expand All @@ -418,6 +422,7 @@ def execute_command(self,command,env=None,channel=None):
self._block(channel.wait_eof)
self._block(channel.close)
ret = self._block(channel.get_exit_status)
del channel
return(ret,out)

def start_sftp(self):
Expand Down
10 changes: 8 additions & 2 deletions redssh/redssh.py
Expand Up @@ -157,15 +157,21 @@ def last_error(self):
'''
return(self.client.last_error())

def execute_command(self,command):
def execute_command(self,command,env=None,channel=None,pty=False):
'''
Run a command. This will block as the command executes.
:param command: Command to execute.
:type command: ``str``
:param env: Environment variables to set during ``command``.
:type env: ``dict``
:param channel: Use an existing SSH channel instead of spawning a new one.
:type channel: ``redssh.RedSSH.channel``
:param pty: Request a pty for the command to be executed via.
:type pty: ``bool``
:return: ``tuple (int, str)`` - of ``(return_code, command_output)``
'''
return(self.client.execute_command(command))
return(self.client.execute_command(command,env=env,channel=channel,pty=pty))

def start_sftp(self):
'''
Expand Down
14 changes: 13 additions & 1 deletion tests/test_basics.py
Expand Up @@ -8,7 +8,7 @@
import redssh

from .base_test import base_test as unittest_base

from redssh.clients.libssh2.libssh2 import exceptions as libssh2_exceptions

class RedSSHUnitTest(unittest_base):

Expand Down Expand Up @@ -140,6 +140,18 @@ def test_ssh_keepalive(self):
sshs.wait_for(self.prompt)
sshs.sendline('echo')

def test_exec_command(self):
for client in sorted(redssh.clients.enabled_clients):
with self.subTest(client=client):
redssh.clients.default_client = client
sshs = self.start_ssh_session()
sshs.wait_for(self.prompt)
try:
(ret,out) = sshs.rs.execute_command('echo')
assert ret == 0
except libssh2_exceptions.BadUseError:
pass


if __name__ == '__main__':
unittest.main()
Expand Down

0 comments on commit fc789cf

Please sign in to comment.