0

Because this question seems to aim somewhere else I am going to point my problem here:

In my python script I am using multiple requests to a remote server using ssh:

def ssh(command):
  command = 'ssh SERVER "command"'
  output = subprocess.check_output(
    command, 
    stderr=subprocess.STDOUT,
    shell=True,
    universal_newlines=True
  )
  return output

here I will get the content of file1 as output.

I have now multiple methods which use this function:

def show_one():
  ssh('cat file1')

def show_two():
  ssh('cat file2')

def run():
  one = show_one()
  print(one)
  two = show_two()
  print(two)

Executing run() will open and close the ssh connection for each show_* method which makes it pretty slow.

Solutions:

  1. I can put:
Host SERVER
  ControlMaster auto
  ControlPersist yes
  ControlPath ~/.ssh/socket-%r@%h:%p

into my .ssh/config but I would like to solve this within python.

  1. There is the ssh flag -T to keep a connection open, and in the before mentioned Question one answer was to use this with Popen() and p.communicate() but it is not possible to get the output between the communicates because it throws an error ValueError: Cannot send input after starting communication

  2. I could somehow change my functions to execute a single ssh command like echo "--show1--"; cat file1; echo "--show2--"; cat file2 but this looks hacky to me and I hope there is a better method to just keep the ssh connection open and use it like normal.

  3. What I would like to have: For example a pythonic/bashic to do the same as I can configure in the .ssh/config (see 1.) to declare a specific socket for the connection and explicitly open, use, close it

Asara
  • 2,791
  • 3
  • 26
  • 55
  • Did you consider creating an SSH object and passing it to the functions ? so you will always have 1 connection open and you pass it tp the functions who need it. – idan357 Sep 05 '21 at 11:24
  • this is something I have in mind, but how to `create an SSH object` ? – Asara Sep 05 '21 at 11:54

1 Answers1

0

Try to create ssh object from class and pass it to the functions:

import paramiko
from pythonping import ping
from scp import SCPClient

class SSH():

def __init__(self, ip='192.168.1.1', username='user', password='pass',connect=True,Timeout=10):
    self.ip = ip
    self.username = username
    self.password = password
    self.Timeout=Timeout
    self.ssh = paramiko.SSHClient()
    self.ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())

    if connect:
        self.OpenConnection()
        self.scp = SCPClient(self.ssh.get_transport())

def OpenConnection(self):
    try:
        skip_ping = False
        ping_res=False
        log.info('Sending ping to host (timeout=3,count=3) :'+self.ip)
        try:
            PingRes = ping(target=self.ip,timeout=3,count=3, verbose=True)
            log.info('Ping to host result :' + str(PingRes.success()))
            ping_res=PingRes.success()
        except:
            skip_ping=True
        if ping_res or skip_ping:
            log.info('Starting to open connection....')
            self.ssh.connect(hostname=self.ip, username=self.username, password=self.password, timeout=self.Timeout, auth_timeout=self.Timeout,banner_timeout=self.Timeout)
            self.scp = SCPClient(self.ssh.get_transport())
            log.info('Connection open')
            return True
        else:
            log.error('ssh OpenConnection failed: No Ping to host')
            return False

myssh = SSH(ip='192.168.1.1',password='mypass',username='myusername')

the ping result is wrapped in try catch because sometimes my machine return an error you can remove it and just verify a ping to the host. The self.scp is for file transfer.

idan357
  • 342
  • 6
  • 17
  • ok there is a lot of verbose code, but I guess the important thing here is that you suggest to use the `paramiko ssh client` I will try if this solves my question here – Asara Sep 05 '21 at 13:13
  • Yes the basic is paramiko – idan357 Sep 06 '21 at 14:13