3737
3838class SSHClient (object ):
3939 """Wrapper class over paramiko.SSHClient with sane defaults
40- Honours ~/.ssh/config and /etc/ssh/ssh_config entries for host username \
41- overrides"""
42-
40+ Honours ``~/.ssh/config`` and ``/etc/ssh/ssh_config`` host entries
41+ for host username overrides
42+ """
43+
4344 def __init__ (self , host ,
4445 user = None , password = None , port = None ,
4546 pkey = None , forward_ssh_agent = True ,
@@ -48,52 +49,51 @@ def __init__(self, host,
4849 proxy_port = 22 , proxy_user = None , proxy_password = None ,
4950 proxy_pkey = None , channel_timeout = None ,
5051 _openssh_config_file = None ):
51- """Connect to host honouring any user set configuration in ~/.ssh/config \
52- or /etc/ssh/ssh_config
53-
52+ """
5453 :param host: Hostname to connect to
5554 :type host: str
56- :param user: (Optional) User to login as. Defaults to logged in user or \
57- user from ~/.ssh/config if set
55+ :param user: (Optional) User to login as. Defaults to logged in user or
56+ user from ~/.ssh/config if set
5857 :type user: str
59- :param password: (Optional) Password to use for login. Defaults to\
60- no password
58+ :param password: (Optional) Password to use for login. Defaults to
59+ no password
6160 :type password: str
62- :param port: (Optional) Port number to use for SSH connection. Defaults\
63- to None which uses SSH default
61+ :param port: (Optional) Port number to use for SSH connection. Defaults
62+ to `` None`` which uses SSH default
6463 :type port: int
6564 :param pkey: (Optional) Client's private key to be used to connect with
6665 :type pkey: :py:class:`paramiko.pkey.PKey`
67- :param num_retries: (Optional) Number of retries for connection attempts\
68- before the client gives up. Defaults to 3.
66+ :param num_retries: (Optional) Number of retries for connection attempts
67+ before the client gives up. Defaults to 3.
6968 :type num_retries: int
70- :param timeout: (Optional) Number of seconds to timeout connection attempts \
71- before the client gives up. Defaults to 10.
69+ :param timeout: (Optional) Number of seconds to timeout connection
70+ attempts before the client gives up
7271 :type timeout: int
73- :param forward_ssh_agent: (Optional) Turn on SSH agent forwarding - \
74- equivalent to `ssh -A` from the `ssh` command line utility. \
75- Defaults to True if not set.
72+ :param forward_ssh_agent: (Optional) Turn on SSH agent forwarding -
73+ equivalent to `ssh -A` from the `ssh` command line utility.
74+ Defaults to True if not set.
7675 :type forward_ssh_agent: bool
77- :param agent: (Optional) Override SSH agent object with the provided. \
78- This allows for overriding of the default paramiko behaviour of \
79- connecting to local SSH agent to lookup keys with our own SSH agent \
80- object.
76+ :param agent: (Optional) Override SSH agent object with the provided.
77+ This allows for overriding of the default paramiko behaviour of
78+ connecting to local SSH agent to lookup keys with our own SSH agent
79+ object.
8180 :type agent: :py:class:`paramiko.agent.Agent`
82- :param forward_ssh_agent: (Optional) Turn on SSH agent forwarding - \
83- equivalent to `ssh -A` from the `ssh` command line utility. \
84- Defaults to True if not set.
81+ :param forward_ssh_agent: (Optional) Turn on SSH agent forwarding -
82+ equivalent to `ssh -A` from the `ssh` command line utility.
83+ Defaults to True if not set.
8584 :type forward_ssh_agent: bool
86- :param proxy_host: (Optional) SSH host to tunnel connection through \
87- so that SSH clients connects to self.host via client -> proxy_host -> host
85+ :param proxy_host: (Optional) SSH host to tunnel connection through
86+ so that SSH clients connects to self.host via
87+ client -> proxy_host -> host
8888 :type proxy_host: str
89- :param proxy_port: (Optional) SSH port to use to login to proxy host if \
90- set. Defaults to 22.
89+ :param proxy_port: (Optional) SSH port to use to login to proxy host if
90+ set. Defaults to 22.
9191 :type proxy_port: int
92- :param channel_timeout: (Optional) Time in seconds before an SSH operation \
93- times out.
92+ :param channel_timeout: (Optional) Time in seconds before an SSH
93+ operation times out.
9494 :type channel_timeout: int
95- :param allow_agent: (Optional) set to False to disable connecting to \
96- the SSH agent
95+ :param allow_agent: (Optional) set to False to disable connecting to
96+ the SSH agent
9797 :type allow_agent: bool
9898 """
9999 try :
@@ -117,27 +117,29 @@ def __init__(self, host,
117117 self .num_retries = num_retries
118118 self .timeout = timeout
119119 self .channel_timeout = channel_timeout
120- self .proxy_host , self .proxy_port , self .proxy_user , self . proxy_password , \
121- self .proxy_pkey = proxy_host , proxy_port , proxy_user , \
122- proxy_password , proxy_pkey
120+ self .proxy_host , self .proxy_port , self .proxy_user , \
121+ self .proxy_password , self . proxy_pkey = proxy_host , proxy_port , \
122+ proxy_user , proxy_password , proxy_pkey
123123 self .proxy_client = None
124124 if self .proxy_host and self .proxy_port :
125- logger .debug ("Proxy configured for destination host %s - Proxy host: %s:%s" ,
126- self .host , self .proxy_host , self .proxy_port ,)
125+ logger .debug (
126+ "Proxy configured for destination host %s - Proxy host: %s:%s" ,
127+ self .host , self .proxy_host , self .proxy_port ,)
127128 self ._connect_tunnel ()
128129 else :
129130 self ._connect (self .client , self .host , self .port )
130131
131132 def _connect_tunnel (self ):
132133 """Connects to SSH server via an intermediate SSH tunnel server.
133- client (me) -> tunnel (ssh server to proxy through) -> \
134- destination (ssh server to run command)
134+ client (me) -> tunnel (ssh server to proxy through) ->
135+ ``self.host`` (ssh server to run command)
135136
136137 :rtype: :py:class:`paramiko.SSHClient` Client to remote SSH destination
137138 via intermediate SSH tunnel server.
138139 """
139140 self .proxy_client = paramiko .SSHClient ()
140- self .proxy_client .set_missing_host_key_policy (paramiko .MissingHostKeyPolicy ())
141+ self .proxy_client .set_missing_host_key_policy (
142+ paramiko .MissingHostKeyPolicy ())
141143 self ._connect (self .proxy_client , self .proxy_host , self .proxy_port ,
142144 user = self .proxy_user , password = self .proxy_password ,
143145 pkey = self .proxy_pkey )
@@ -148,21 +150,26 @@ def _connect_tunnel(self):
148150 'direct-tcpip' , (self .host , self .port ,), ('127.0.0.1' , 0 ),
149151 timeout = self .timeout )
150152 sleep (0 )
151- return self ._connect (self .client , self .host , self .port , sock = proxy_channel )
153+ return self ._connect (self .client , self .host , self .port ,
154+ sock = proxy_channel )
152155 except (ChannelException , paramiko .SSHException ) as ex :
153156 error_type = ex .args [1 ] if len (ex .args ) > 1 else ex .args [0 ]
154- raise ConnectionErrorException ("Error connecting to host '%s:%s' - %s" ,
155- self . host , self . port ,
156- str (error_type ))
157+ raise ConnectionErrorException (
158+ "Error connecting to host '%s:%s' - %s" ,
159+ self . host , self . port , str (error_type ))
157160
158161 def _connect (self , client , host , port , sock = None , retries = 1 ,
159162 user = None , password = None , pkey = None ):
160163 """Connect to host
161164
162- :raises: :py:class:`pssh.exceptions.AuthenticationException` on authentication error
163- :raises: :py:class:`pssh.exceptions.UnknownHostException` on DNS resolution error
164- :raises: :py:class:`pssh.exceptions.ConnectionErrorException` on error connecting
165- :raises: :py:class:`pssh.exceptions.SSHException` on other undefined SSH errors
165+ :raises: :py:class:`pssh.exceptions.AuthenticationException`
166+ on authentication error
167+ :raises: :py:class:`pssh.exceptions.UnknownHostException`
168+ on DNS resolution error
169+ :raises: :py:class:`pssh.exceptions.ConnectionErrorException`
170+ on error connecting
171+ :raises: :py:class:`pssh.exceptions.SSHException` on other undefined
172+ SSH errors
166173 """
167174 try :
168175 client .connect (host , username = user if user else self .user ,
@@ -188,9 +195,10 @@ def _connect(self, client, host, port, sock=None, retries=1,
188195 return self ._connect (client , host , port , sock = sock ,
189196 retries = retries + 1 )
190197 error_type = ex .args [1 ] if len (ex .args ) > 1 else ex .args [0 ]
191- raise ConnectionErrorException ("Error connecting to host '%s:%s' - %s - retry %s/%s" ,
192- self .host , self .port ,
193- str (error_type ), retries , self .num_retries ,)
198+ raise ConnectionErrorException (
199+ "Error connecting to host '%s:%s' - %s - retry %s/%s" ,
200+ self .host , self .port , str (error_type ), retries ,
201+ self .num_retries ,)
194202 except paramiko .AuthenticationException as ex :
195203 msg = "Authentication error while connecting to %s:%s."
196204 raise AuthenticationException (msg , host , port )
@@ -206,43 +214,45 @@ def exec_command(self, command, sudo=False, user=None,
206214 use_shell = True , use_pty = True ):
207215 """Wrapper to :py:func:`paramiko.SSHClient.exec_command`
208216
209- Opens a new SSH session with a new pty and runs command before yielding
217+ Opens a new SSH session with a new pty and runs command before yielding
210218 the main gevent loop to allow other greenlets to execute.
211219
212220 :param command: Command to execute
213221 :type command: str
214222 :param sudo: (Optional) Run with sudo. Defaults to False
215223 :type sudo: bool
216- :param user: (Optional) User to switch to via sudo to run command as. \
217- Defaults to user running the python process
224+ :param user: (Optional) User to switch to via sudo to run command as.
225+ Defaults to user running the python process
218226 :type user: str
219- :param shell: (Optional) Shell override to use instead of user login \
220- configured shell. For example ``shell='bash -c'``
221- :param use_shell: (Optional) Force use of shell on/off. \
222- Defaults to `True` for on
227+ :param shell: (Optional) Shell override to use instead of user login
228+ configured shell. For example ``shell='bash -c'``
229+ :param use_shell: (Optional) Force use of shell on/off.
230+ Defaults to `True` for on
223231 :type use_shell: bool
224- :param use_pty: (Optional) Enable/Disable use of pseudo terminal \
225- emulation. This is required in vast majority of cases, exception \
226- being where a shell is not used and/or stdout/stderr/stdin buffers \
227- are not required. Defaults to ``True``
232+ :param use_pty: (Optional) Enable/Disable use of pseudo terminal
233+ emulation. This is required in vast majority of cases, exception
234+ being where a shell is not used and/or stdout/stderr/stdin buffers
235+ are not required. Defaults to ``True``
228236 :type use_pty: bool
229- :param kwargs: (Optional) Keyword arguments to be passed to remote \
230- command
237+ :param kwargs: (Optional) Keyword arguments to be passed to remote
238+ command
231239 :type kwargs: dict
232- :rtype: Tuple of `(channel, hostname, stdout, stderr, stdin)`. \
233- Channel is the remote SSH channel, needed to ensure all of stdout has \
234- been got, hostname is remote hostname the copy is to, stdout and \
235- stderr are buffers containing command output.
240+ :rtype: Tuple of `(channel, hostname, stdout, stderr, stdin)`.
241+ Channel is the remote SSH channel, needed to ensure all of stdout has
242+ been got, hostname is remote hostname the copy is to, stdout and
243+ stderr are buffers containing command output and stdin is standard
244+ input channel
236245 """
237246 channel = self .client .get_transport ().open_session ()
238247 if self .forward_ssh_agent :
239- agent_handler = paramiko .agent .AgentRequestHandler (channel )
248+ agent_handler = paramiko .agent .AgentRequestHandler ( # noqa: F841
249+ channel )
240250 if use_pty :
241251 channel .get_pty ()
242252 if self .channel_timeout :
243253 channel .settimeout (self .channel_timeout )
244254 stdout , stderr , stdin = channel .makefile ('rb' ), \
245- channel .makefile_stderr ('rb' ), channel .makefile ('wb' )
255+ channel .makefile_stderr ('rb' ), channel .makefile ('wb' )
246256 for _char in ['\\ ' , '"' , '$' , '`' ]:
247257 command = command .replace (_char , r'\%s' % (_char ,))
248258 shell = '$SHELL -c' if not shell else shell
@@ -353,7 +363,7 @@ def copy_file(self, local_file, remote_file, recurse=False,
353363 sftp = None ):
354364 """Copy local file to host via SFTP/SCP
355365
356- Copy is done natively using SFTP/SCP version 2 protocol, no scp command \
366+ Copy is done natively using SFTP/SCP version 2 protocol, no scp command
357367 is used or required.
358368
359369 :param local_file: Local filepath to copy to remote host
@@ -363,8 +373,8 @@ def copy_file(self, local_file, remote_file, recurse=False,
363373 :param recurse: Whether or not to descend into directories recursively.
364374 :type recurse: bool
365375
366- :raises: :py:class:`ValueError` when a directory is supplied to ``local_file`` \
367- and ``recurse`` is not set
376+ :raises: :py:class:`ValueError` when a directory is supplied to
377+ ``local_file`` and ``recurse`` is not set
368378 :raises: :py:class:`IOError` on I/O errors writing files
369379 :raises: :py:class:`OSError` on OS errors like permission denied
370380 """
@@ -394,7 +404,7 @@ def copy_remote_file(self, remote_file, local_file, recurse=False,
394404 sftp = None ):
395405 """Copy remote file to local host via SFTP/SCP
396406
397- Copy is done natively using SFTP/SCP version 2, no scp command \
407+ Copy is done natively using SFTP/SCP version 2, no scp command
398408 is used or required.
399409
400410 :param remote_file: Remote filepath to copy from
@@ -404,8 +414,8 @@ def copy_remote_file(self, remote_file, local_file, recurse=False,
404414 :param recurse: Whether or not to recursively copy directories
405415 :type recurse: bool
406416
407- :raises: :py:class:`ValueError` when a directory is supplied to remote_file \
408- and recurse is not set
417+ :raises: :py:class:`ValueError` when a directory is supplied to
418+ ``local_file`` and `` recurse`` is not set
409419 :raises: :py:class:`IOError` on I/O errors creating directories or file
410420 :raises: :py:class:`OSError` on OS errors like permission denied
411421 """
0 commit comments