Skip to content

Commit f2a53d1

Browse files
authored
Conn chain (#138)
* SSH Proxy support: connection chain with optional creds map validated in the wild, tests will be updated later (functionality is required ASAP) * fix black
1 parent d79680a commit f2a53d1

15 files changed

+678
-77
lines changed

doc/source/ExecResult.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -210,7 +210,7 @@ API: ExecResult
210210

211211
:param item: index
212212
:type item: typing.Union[int, slice, typing.Iterable[typing.Union[int, slice, ellipsis]]]
213-
:returns: Joined selected lines
213+
:return: Joined selected lines
214214
:rtype: str
215215
:raises TypeError: Unexpected key
216216

doc/source/SSHClient.rst

Lines changed: 56 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ API: SSHClient and SSHAuth.
1010
1111
SSHClient helper.
1212

13-
.. py:method:: __init__(host, port=22, username=None, password=None, private_keys=None, auth=None, *, verbose=True, ssh_config=None, sock=None)
13+
.. py:method:: __init__(host, port=22, username=None, password=None, *, private_keys=None, auth=None, verbose=True, ssh_config=None, ssh_auth_map=None, sock=None, keepalive=True)
1414
1515
:param host: remote hostname
1616
:type host: ``str``
@@ -28,10 +28,18 @@ API: SSHClient and SSHAuth.
2828
:type verbose: bool
2929
:param ssh_config: SSH configuration for connection. Maybe config path, parsed as dict and paramiko parsed.
3030
:type ssh_config: typing.Union[str, paramiko.SSHConfig, typing.Dict[str, typing.Dict[str, typing.Union[str, int, bool, typing.List[str]]]], HostsSSHConfigs, None]
31+
:param ssh_auth_map: SSH authentication information mapped to host names. Useful for complex SSH Proxy cases.
32+
:type ssh_auth_map: typing.Optional[typing.Union[typing.Dict[str, ssh_auth.SSHAuth], ssh_auth.SSHAuthMapping]]
3133
:param sock: socket for connection. Useful for ssh proxies support
3234
:type sock: typing.Optional[typing.Union[paramiko.ProxyCommand, paramiko.Channel, socket.socket]]
35+
:param keepalive: keepalive mode
36+
:type keepalive: bool
3337

3438
.. note:: auth has priority over username/password/private_keys
39+
.. note::
40+
41+
for proxy connection auth information is collected from SSHConfig
42+
if ssh_auth_map record is not available
3543

3644
.. py:attribute:: log_mask_re
3745
@@ -230,7 +238,7 @@ API: SSHClient and SSHAuth.
230238
.. versionchanged:: 1.2.0 default timeout 1 hour
231239
.. versionchanged:: 3.2.0 Exception class can be substituted
232240

233-
.. py:method:: proxy_to(host, port=None, username=None, password=None, private_keys=None, auth=None, *, verbose=True, ssh_config=None, )
241+
.. py:method:: proxy_to(host, port=None, username=None, password=None, *, private_keys=None, auth=None, verbose=True, ssh_config=None, ssh_auth_map=None, keepalive=True)
234242
235243
Start new SSH connection using current as proxy.
236244

@@ -250,14 +258,18 @@ API: SSHClient and SSHAuth.
250258
:type verbose: bool
251259
:param ssh_config: SSH configuration for connection. Maybe config path, parsed as dict and paramiko parsed.
252260
:type ssh_config: typing.Union[str, paramiko.SSHConfig, typing.Dict[str, typing.Dict[str, typing.Union[str, int, bool, typing.List[str]]]], HostsSSHConfigs, None]
253-
:returns: new ssh client instance using current as a proxy
261+
:param ssh_auth_map: SSH authentication information mapped to host names. Useful for complex SSH Proxy cases.
262+
:type ssh_auth_map: typing.Optional[typing.Union[typing.Dict[str, ssh_auth.SSHAuth], ssh_auth.SSHAuthMapping]]
263+
:param keepalive: keepalive mode
264+
:type keepalive: bool
265+
:return: new ssh client instance using current as a proxy
254266
:rtype: SSHClientBase
255267

256268
.. note:: auth has priority over username/password/private_keys
257269

258270
.. versionadded:: 6.0.0
259271

260-
.. py:method:: execute_through_host(hostname, command, auth=None, target_port=22, verbose=False, timeout=1*60*60, *, stdin=None, log_mask_re="", get_pty=False, width=80, height=24, **kwargs)
272+
.. py:method:: execute_through_host(hostname, command, *, auth=None, port=22, verbose=False, timeout=1*60*60, stdin=None, log_mask_re="", get_pty=False, width=80, height=24, **kwargs)
261273
262274
Execute command on remote host through currently connected host.
263275

@@ -267,8 +279,8 @@ API: SSHClient and SSHAuth.
267279
:type command: ``str``
268280
:param auth: credentials for target machine
269281
:type auth: typing.Optional[SSHAuth]
270-
:param target_port: target port
271-
:type target_port: ``int``
282+
:param port: target port
283+
:type port: ``int``
272284
:param verbose: Produce log.info records for command call and output
273285
:type verbose: ``bool``
274286
:param timeout: Timeout for command execution.
@@ -290,6 +302,8 @@ API: SSHClient and SSHAuth.
290302
.. versionchanged:: 3.2.0 Expose pty options as optional keyword-only arguments
291303
.. versionchanged:: 3.2.0 Exception class can be substituted
292304
.. versionchanged:: 4.0.0 Expose stdin and log_mask_re as optional keyword-only arguments
305+
.. versionchanged:: 6.0.0 Move channel open to separate method and make proper ssh-proxy usage
306+
.. versionchanged:: 6.0.0 only hostname and command are positional argument, target_port changed to port.
293307

294308
.. py:classmethod:: execute_together(remotes, command, timeout=1*60*60, expected=(0,), raise_on_err=True, *, stdin=None, log_mask_re="", exception_class=ParallelCallProcessError, **kwargs)
295309
@@ -504,6 +518,39 @@ API: SSHClient and SSHAuth.
504518
:raises paramiko.AuthenticationException: Authentication failed.
505519

506520

521+
.. py:class::SSHAuthMapping(typing.Dict[str, SSHAuth])
522+
523+
Specific dictionary for ssh hostname - auth mapping.
524+
525+
keys are always string and saved/collected lowercase.
526+
527+
.. py:method:: __init__(auth_dict=None, **auth_mapping)
528+
529+
Specific dictionary for ssh hostname - auth mapping.
530+
531+
:param auth_dict: original hostname - source ssh auth mapping (dictionary of SSHAuthMapping)
532+
:type auth_dict: typing.Optional[typing.Union[typing.Dict[str, SSHAuth], SSHAuthMapping]]
533+
:param auth_mapping: SSHAuth setting via **kwargs
534+
:type auth_mapping: SSHAuth
535+
:raises TypeError: Incorrect type of auth dict or auth object
536+
537+
.. py:method:: get_with_alt_hostname(hostname, *host_names, default=None)
538+
539+
Try to guess hostname with credentials.
540+
541+
:param hostname: expected target hostname
542+
:type hostname: str
543+
:param host_names: alternate host names
544+
:type host_names: str
545+
:param default: credentials if hostname not found
546+
:type default: typing.Optional[SSHAuth]
547+
:return: guessed credentials
548+
:rtype: typing.Optional[SSHAuth]
549+
:raises TypeError: Default SSH Auth object is not SSHAuth
550+
551+
Method used in cases, when 1 host share 2 or more names in config.
552+
553+
507554
.. py:class:: SshExecuteAsyncResult
508555
509556
Typed NamedTuple
@@ -543,7 +590,7 @@ API: SSHClient and SSHAuth.
543590

544591
:param key: nonexistent key
545592
:type key: str
546-
:returns: generated ssh config for host
593+
:return: generated ssh config for host
547594
:rtype: SSHConfig
548595
:raises KeyError: key is not string
549596

@@ -585,7 +632,7 @@ API: SSHClient and SSHAuth.
585632
Construct config from Paramiko parsed file.
586633

587634
:param ssh_config: paramiko parsed ssh config or it reconstruction as a dict,
588-
:returns: SSHConfig with supported values from config
635+
:return: SSHConfig with supported values from config
589636

590637
.. py:attribute:: as_dict
591638
@@ -598,7 +645,7 @@ API: SSHClient and SSHAuth.
598645

599646
:param ssh_config: Other ssh config
600647
:type ssh_config: SSHConfig
601-
:returns: Composite from 2 configs with priority of second one
648+
:return: Composite from 2 configs with priority of second one
602649
:rtype: SSHConfig
603650

604651
.. py:attribute:: hostname

0 commit comments

Comments
 (0)