Skip to content

Commit

Permalink
Support ssh proxy command
Browse files Browse the repository at this point in the history
  • Loading branch information
myakove authored and lukas-bednar committed Mar 8, 2022
1 parent dca6c35 commit cbae844
Show file tree
Hide file tree
Showing 4 changed files with 61 additions and 8 deletions.
8 changes: 8 additions & 0 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,14 @@ Using SSH key with disabled algorithms on paramiko SSHClient connect (Used when
h.executor(user).run_cmd(['echo', 'Use pkey and disabled algorithms for old openSSH connection'])
Using with SSH ProxyCommand
.. code:: python
proxy_command = 'some proxy command'
h = Host(hostname="hostname")
host.executor_factory = ssh.RemoteExecutorFactory(sock=proxy_command)
h.executor(user).run_cmd(['echo', 'Use SSH with ProxyCommand'])
Features
--------

Expand Down
21 changes: 17 additions & 4 deletions rrmngmnt/host.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import warnings

import netaddr

from rrmngmnt import errors
from rrmngmnt import power_manager
from rrmngmnt import ssh
Expand Down Expand Up @@ -56,15 +57,24 @@ def process(self, msg, kwargs):
kwargs,
)

def __init__(self, ip, service_provider=None):
def __init__(self, ip=None, service_provider=None, hostname=None):
"""
Args:
ip (str): IP address of machine or resolvable FQDN
service_provider (Service): system service handler
hostname (str): hostname of machine (Used with ProxyCommand)
"""
super(Host, self).__init__()
if not netaddr.valid_ipv4(ip) and not netaddr.valid_ipv6(ip):
ip = fqdn2ip(ip)
if hostname:
# When using ProxyCommand host is not IP and does not have fqdn.
ip = hostname
else:
if not netaddr.valid_ipv4(ip) and not netaddr.valid_ipv6(ip):
ip = fqdn2ip(ip)

if not ip:
raise ValueError("ip or hostname is required")

self.ip = ip
self.users = list()
self._executor_user = None
Expand Down Expand Up @@ -233,7 +243,10 @@ def executor(self, user=None, pkey=False, sudo=False):
ef = copy.copy(self.executor_factory)
ef.use_pkey = pkey
return ef.build(self, user, self.sudo)
return self.executor_factory.build(self, user, sudo=self.sudo)

return self.executor_factory.build(
self, user, sudo=self.sudo
)

def run_command(
self, command, input_=None, tcp_timeout=None, io_timeout=None,
Expand Down
18 changes: 14 additions & 4 deletions rrmngmnt/ssh.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,8 @@ def open(self):
timeout=self._timeout,
pkey=self.pkey,
port=self._executor.port,
disabled_algorithms=self._executor.disabled_algorithms
disabled_algorithms=self._executor.disabled_algorithms,
sock=self._executor.sock,
)
except (socket.gaierror, socket.herror) as ex:
args = list(ex.args)
Expand Down Expand Up @@ -222,21 +223,25 @@ def __init__(self,
use_pkey=False,
port=22,
sudo=False,
disabled_algorithms=None):
disabled_algorithms=None,
sock=None,
):
"""
Args:
use_pkey (bool): Use ssh private key in the connection
user (instance of User): User
address (str): Ip / hostname
port (int): Port to connect
sudo (bool): Use sudo to execute command.
sock (ProxyCommand): Proxy command to use.
"""
super(RemoteExecutor, self).__init__(user)
self.address = address
self.use_pkey = use_pkey
self.port = port
self.sudo = sudo
self.disabled_algorithms = disabled_algorithms
self.sock = sock
if use_pkey:
warnings.warn(
"Parameter 'use_pkey' is deprecated and will be removed in "
Expand Down Expand Up @@ -335,10 +340,13 @@ def wait_for_connectivity_state(


class RemoteExecutorFactory(ExecutorFactory):
def __init__(self, use_pkey=False, port=22, disabled_algorithms=None):
def __init__(
self, use_pkey=False, port=22, disabled_algorithms=None, sock=None
):
self.use_pkey = use_pkey
self.port = port
self.disabled_algorithms = disabled_algorithms
self.sock = sock
if use_pkey:
warnings.warn(
"Parameter 'use_pkey' is deprecated and will be removed in "
Expand All @@ -352,4 +360,6 @@ def build(self, host, user, sudo=False):
use_pkey=self.use_pkey,
port=self.port,
sudo=sudo,
disabled_algorithms=self.disabled_algorithms)
disabled_algorithms=self.disabled_algorithms,
sock=paramiko.ProxyCommand(self.sock) if self.sock else self.sock,
)
22 changes: 22 additions & 0 deletions tests/test_executor.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
from rrmngmnt import Host, User

from tests.common import FakeExecutorFactory


def get_host(hostname='test-host'):
return Host(hostname=hostname)


def test_executor_with_proxy_command():
data = {
'which systemctl': (0, '/usr/bin/systemctl', ''),
}
host = get_host()
sock = 'my proxy command --stdio=true test-host 22'
host_user = User(name="user", password="user")
host.executor_user = host_user
host.executor_factory = FakeExecutorFactory(
cmd_to_data=data, files_content=None
)
host.executor_factory.sock = sock
host.executor().run_cmd(['which', 'systemctl'])

0 comments on commit cbae844

Please sign in to comment.