I would like to write a script that performs the following Linux commands sequence:
rsh rr01 ( here the system will ask for password )
ssh rr02 ( here the system will ask for password again)
activate my app on some file
I was naively (and stupidly) tried to accomplish that with a simple os.system
bear in mind I using python 2.3 and would like to avoid adding modules (if possible).
Thanks in advance!
[EDIT] Check out also another example using paramiko on http://code.google.com/p/lexel-intern0t/source/browse/trunk/Python/ssh_client.py.
The script found on http://media.commandline.org.uk//code/ssh.txt may help you. It includes os module (to find the keys) and tempfile module for logging purposes, both found in python 2.3 global module index ( http://docs.python.org/release/2.3/modindex.html ) and paramiko ( http://www.lag.net/paramiko/docs/ ) for the SSH2 protocol implementation, which is supposed to work on python 2.3 and above. It's a simple piece of code:
"""Friendly Python SSH2 interface."""
import os
import tempfile
import paramiko
class Connection(object):
"""Connects and logs into the specified hostname.
Arguments that are not given are guessed from the environment."""
def __init__(self,
host,
username = None,
private_key = None,
password = None,
port = 22,
):
self._sftp_live = False
self._sftp = None
if not username:
username = os.environ['LOGNAME']
# Log to a temporary file.
templog = tempfile.mkstemp('.txt', 'ssh-')[1]
paramiko.util.log_to_file(templog)
# Begin the SSH transport.
self._transport = paramiko.Transport((host, port))
self._tranport_live = True
# Authenticate the transport.
if password:
# Using Password.
self._transport.connect(username = username, password = password)
else:
# Use Private Key.
if not private_key:
# Try to use default key.
if os.path.exists(os.path.expanduser('~/.ssh/id_rsa')):
private_key = '~/.ssh/id_rsa'
elif os.path.exists(os.path.expanduser('~/.ssh/id_dsa')):
private_key = '~/.ssh/id_dsa'
else:
raise TypeError, "You have not specified a password or key."
private_key_file = os.path.expanduser(private_key)
rsa_key = paramiko.RSAKey.from_private_key_file(private_key_file)
self._transport.connect(username = username, pkey = rsa_key)
def _sftp_connect(self):
"""Establish the SFTP connection."""
if not self._sftp_live:
self._sftp = paramiko.SFTPClient.from_transport(self._transport)
self._sftp_live = True
def get(self, remotepath, localpath = None):
"""Copies a file between the remote host and the local host."""
if not localpath:
localpath = os.path.split(remotepath)[1]
self._sftp_connect()
self._sftp.get(remotepath, localpath)
def put(self, localpath, remotepath = None):
"""Copies a file between the local host and the remote host."""
if not remotepath:
remotepath = os.path.split(localpath)[1]
self._sftp_connect()
self._sftp.put(localpath, remotepath)
def execute(self, command):
"""Execute the given commands on a remote machine."""
channel = self._transport.open_session()
channel.exec_command(command)
output = channel.makefile('rb', -1).readlines()
if output:
return output
else:
return channel.makefile_stderr('rb', -1).readlines()
def close(self):
"""Closes the connection and cleans up."""
# Close SFTP Connection.
if self._sftp_live:
self._sftp.close()
self._sftp_live = False
# Close the SSH Transport.
if self._tranport_live:
self._transport.close()
self._tranport_live = False
def __del__(self):
"""Attempt to clean up if not explicitly closed."""
self.close()
def main():
"""Little test when called directly."""
# Set these to your own details.
myssh = Connection('example.com')
myssh.put('ssh.py')
myssh.close()
# start the ball rolling.
if __name__ == "__main__":
main()
Related
I need to trigger a python script every time an email is received by my webserver on a specific account. I will also need the email to be passed to the script as an argument. My webserver is using Dovecot. How do I go about doing this?
I recommend you have a look at Twisted and specifically its IMAP and POP protocols and client modules.
As an example:
#!/usr/bin/env python
# Copyright (c) Twisted Matrix Laboratories.
# See LICENSE for details.
"""
Simple IMAP4 client which displays the subjects of all messages in a
particular mailbox.
"""
import sys
from twisted.internet import protocol
from twisted.internet import ssl
from twisted.internet import defer
from twisted.internet import stdio
from twisted.mail import imap4
from twisted.protocols import basic
from twisted.python import util
from twisted.python import log
class TrivialPrompter(basic.LineReceiver):
from os import linesep as delimiter
promptDeferred = None
def prompt(self, msg):
assert self.promptDeferred is None
self.display(msg)
self.promptDeferred = defer.Deferred()
return self.promptDeferred
def display(self, msg):
self.transport.write(msg)
def lineReceived(self, line):
if self.promptDeferred is None:
return
d, self.promptDeferred = self.promptDeferred, None
d.callback(line)
class SimpleIMAP4Client(imap4.IMAP4Client):
"""
A client with callbacks for greeting messages from an IMAP server.
"""
greetDeferred = None
def serverGreeting(self, caps):
self.serverCapabilities = caps
if self.greetDeferred is not None:
d, self.greetDeferred = self.greetDeferred, None
d.callback(self)
class SimpleIMAP4ClientFactory(protocol.ClientFactory):
usedUp = False
protocol = SimpleIMAP4Client
def __init__(self, username, onConn):
self.ctx = ssl.ClientContextFactory()
self.username = username
self.onConn = onConn
def buildProtocol(self, addr):
"""
Initiate the protocol instance. Since we are building a simple IMAP
client, we don't bother checking what capabilities the server has. We
just add all the authenticators twisted.mail has. Note: Gmail no
longer uses any of the methods below, it's been using XOAUTH since
2010.
"""
assert not self.usedUp
self.usedUp = True
p = self.protocol(self.ctx)
p.factory = self
p.greetDeferred = self.onConn
p.registerAuthenticator(imap4.PLAINAuthenticator(self.username))
p.registerAuthenticator(imap4.LOGINAuthenticator(self.username))
p.registerAuthenticator(
imap4.CramMD5ClientAuthenticator(self.username))
return p
def clientConnectionFailed(self, connector, reason):
d, self.onConn = self.onConn, None
d.errback(reason)
def cbServerGreeting(proto, username, password):
"""
Initial callback - invoked after the server sends us its greet message.
"""
# Hook up stdio
tp = TrivialPrompter()
stdio.StandardIO(tp)
# And make it easily accessible
proto.prompt = tp.prompt
proto.display = tp.display
# Try to authenticate securely
return proto.authenticate(password
).addCallback(cbAuthentication, proto
).addErrback(ebAuthentication, proto, username, password
)
def ebConnection(reason):
"""
Fallback error-handler. If anything goes wrong, log it and quit.
"""
log.startLogging(sys.stdout)
log.err(reason)
return reason
def cbAuthentication(result, proto):
"""
Callback after authentication has succeeded.
Lists a bunch of mailboxes.
"""
return proto.list("", "*"
).addCallback(cbMailboxList, proto
)
def ebAuthentication(failure, proto, username, password):
"""
Errback invoked when authentication fails.
If it failed because no SASL mechanisms match, offer the user the choice
of logging in insecurely.
If you are trying to connect to your Gmail account, you will be here!
"""
failure.trap(imap4.NoSupportedAuthentication)
return proto.prompt(
"No secure authentication available. Login insecurely? (y/N) "
).addCallback(cbInsecureLogin, proto, username, password
)
def cbInsecureLogin(result, proto, username, password):
"""
Callback for "insecure-login" prompt.
"""
if result.lower() == "y":
# If they said yes, do it.
return proto.login(username, password
).addCallback(cbAuthentication, proto
)
return defer.fail(Exception("Login failed for security reasons."))
def cbMailboxList(result, proto):
"""
Callback invoked when a list of mailboxes has been retrieved.
"""
result = [e[2] for e in result]
s = '\n'.join(['%d. %s' % (n + 1, m) for (n, m) in zip(range(len(result)), result)])
if not s:
return defer.fail(Exception("No mailboxes exist on server!"))
return proto.prompt(s + "\nWhich mailbox? [1] "
).addCallback(cbPickMailbox, proto, result
)
def cbPickMailbox(result, proto, mboxes):
"""
When the user selects a mailbox, "examine" it.
"""
mbox = mboxes[int(result or '1') - 1]
return proto.examine(mbox
).addCallback(cbExamineMbox, proto
)
def cbExamineMbox(result, proto):
"""
Callback invoked when examine command completes.
Retrieve the subject header of every message in the mailbox.
"""
return proto.fetchSpecific('1:*',
headerType='HEADER.FIELDS',
headerArgs=['SUBJECT'],
).addCallback(cbFetch, proto
)
def cbFetch(result, proto):
"""
Finally, display headers.
"""
if result:
keys = result.keys()
keys.sort()
for k in keys:
proto.display('%s %s' % (k, result[k][0][2]))
else:
print "Hey, an empty mailbox!"
return proto.logout()
def cbClose(result):
"""
Close the connection when we finish everything.
"""
from twisted.internet import reactor
reactor.stop()
def main():
hostname = raw_input('IMAP4 Server Hostname: ')
port = raw_input('IMAP4 Server Port (the default is 143, 993 uses SSL): ')
username = raw_input('IMAP4 Username: ')
password = util.getPassword('IMAP4 Password: ')
onConn = defer.Deferred(
).addCallback(cbServerGreeting, username, password
).addErrback(ebConnection
).addBoth(cbClose)
factory = SimpleIMAP4ClientFactory(username, onConn)
from twisted.internet import reactor
if port == '993':
reactor.connectSSL(hostname, int(port), factory, ssl.ClientContextFactory())
else:
if not port:
port = 143
reactor.connectTCP(hostname, int(port), factory)
reactor.run()
if __name__ == '__main__':
main()
From here you need to just call your Python script in a subprocess when you detect a new email from your IMAP folder that you're checking... Here you could also use Twisted's Process handling as documented here: https://twistedmatrix.com/documents/13.0.0/core/howto/process.html
Good luck!
IMAP server may notify you about new messages if it supports IDLE command. If it doesn't support it then you could poll the inbox periodically using imaplib from stdlib (code example to retrieve messages from a time period).
imaplib doesn't support IDLE command but it could be easily added e.g., imapidle:
from imapidle import imaplib
m = imaplib.IMAP4_SSL('imap.gmail.com')
m.login('robert', 'pa55w0rd')
m.select()
for uid, msg in m.idle(): # yield new messages
print msg
See also How do I enable push-notification for IMAP (Gmail) using Python imaplib?
I am requesting advice for running concurrent pysftp API commands, such as listing files in a directory and downloading them from a server. It seems that when I test this all requests are blocked until the previous is finished.
I'm using pysftp with Django and I'm not sure how to implement this in a way that will scale a bit so I can have multiple users on the page making requests without them being blocked until another users request has been served.
I tried something like this:
class sftp:
def __init__(self):
self.response = HttpResponse()
self.cnopts = pysftp.CnOpts()
self.cnopts.hostkeys = None
def download(self):
with pysftp.Connection('host.exmaple.com', username='user1', password='test_password',
cnopts=self.cnopts) as sftp:
sftp.getfo(
'/var/lib/stuff/file.mp3',
self.response)
self.response['Content-Type'] = 'audio/mp3'
return self.response
Then in my view I would call something like this:
return sftp().download()
I needed something similar for one of my projects.
I wrote a module that handle listing and reading files on remote server over SSH.
Difference is that it's not using pysftp but paramiko, but it should do the job I guess.
import paramiko
class SSHClient:
__slots__ = ['transport', 'sftp']
def __init__(self, host, user, passw, port):
"""Init connection to SFTP server.
Args:
host (str): Server IP address
user (str): Server username
passw (str): Server password
port (int): connection port
"""
self.transport = paramiko.Transport((host, port))
self.transport.connect(username=user, password=passw)
self.sftp = paramiko.SFTPClient.from_transport(t=self.transport)
def __enter__(self):
return self
def __exit__(self, exception_type, exception_value, traceback):
"""Close SFTP connection"""
self.transport.close()
self.sftp.close()
def list_files(self, remote_path) -> list:
"""List files from specific server directory.
Args:
remote_path (str): SFTP server path directory.
Returns:
list of files & folders in directory.
"""
return self.sftp.listdir(path=remote_path)
def read_remote_file(self, remote_path, filename):
"""Read remote file content from server.
Args:
remote_path (str): SFTP server path.
filename (str): name of file.
"""
return self.sftp.open(
filename='{path}/{file}'.format(path=remote_path, file=filename),
mode='r'
)
def close_conn(self) -> None:
"""Close SFTP connection"""
self.transport.close()
self.sftp.close()
Then you could download a file using the content fetched using read_remote_file() to one of your views in your Django app.
I have a directory containing some files and sub-directories on my local machine that is generated by a daily Python script running. And then I want to copy all those generated files in a directory to the server and then run some series of commands on it by ssh using python package paramiko.
I want to add little code to securely copy that entire directory and files and sub-directories inside it to to my server over SSH/SCP using the paramiko package of python. I can send the individual files using the same but unable to send the entire directory and its content using paramiko. It gives me IOError saying it's a directory.
IOError: [Errno 21] Is a directory: 'temp'
Here is the my code:
from paramiko import SSHClient, AutoAddPolicy
from scp import SCPClient
class SSh(object):
def __init__(self, address, username, password, port=22):
print "Connecting to server."
self._address = address
self._username = username
self._password = password
self._port = port
self.sshObj = None
self.connect()
self.scp = SCPClient(self.sshObj.get_transport())
def sendCommand(self, command):
if(self.sshObj):
stdin, stdout, stderr = self.sshObj.exec_command(command)
while not stdout.channel.exit_status_ready():
# Print data when available
if stdout.channel.recv_ready():
alldata = stdout.channel.recv(1024)
prevdata = b"1"
while prevdata:
prevdata = stdout.channel.recv(1024)
alldata += prevdata
print str(alldata)
else:
print "Connection not opened."
def connect(self):
try:
ssh = SSHClient()
ssh.set_missing_host_key_policy(AutoAddPolicy())
ssh.connect(self._address, port=self._port, username=self._username, password=self._password, timeout=20, look_for_keys=False)
print 'Connected to {} over SSh'.format(self._address)
return True
except Exception as e:
ssh = None
print "Unable to connect to {} over ssh: {}".format(self._address, e)
return False
finally:
self.sshObj = ssh
if __name__ == "__main__":
# Parse and check the arguments
ssh = SSh('10.24.143.190', 'username', 'password')
ssh.scp.put("Valigrind_BB.py") # This works perfectly fine
ssh.scp.put("temp") # IOError over here Is a directory
ssh.sendCommand('ls')
Thank you in advance.
Looking at the source code for SCP, it appears you can pass the parameter "recursive" as a bool to the put() method to specify transferring the contents of a directory recursively. Here is a link to the source code I am talking about. Try changing last part of your code to the following:
if __name__ == "__main__":
# Parse and check the arguments
ssh = SSh('10.24.143.190', 'username', 'password')
ssh.scp.put("Valigrind_BB.py") # This works perfectly fine
ssh.scp.put("temp", recursive=True) # IOError over here Is a directory
ssh.sendCommand('ls')
Also, if you just want to transfer files, you can try rsync as an alternative. The modification to your code above should work though. I hope this helps.
I am having a very specific problem. I use Putty for database management for my small business. We recently had an update and our normal command path to update our records is no longer in use.
We run Putty on all computers in store. Putty is used on a virtual machine with oracle. We have a main computer for the system in which the update occurred.
We normally input ~/Desktop/getdata.sh into putty using root user and it complies an updated list, creates a text file that we use. Unfortunately, the person who created this script no longer works with us.
I am trying to find a way to re execute this file again.
After the update, when we type in ~/Desktop/getdata.sh (after logging in as root) into Putty we get 'directory cannot be found.' I've searched everyday to find this file. However, I did find a getdata.py file and a getdata.bat files.
I can show both scripts if needed, I can update the question.
When I tried to run getdata.py I get
[root#RT_Store-01 /]# ~/Desktop/getdata.py
import: unable to open X server `'.
import: unable to open X server `'.
import: unable to open X server `'.
import: unable to open X server `'.
: command not foundta.py: line 5:
/root/Desktop/getdata.py: line 6: from: command not found
/root/Desktop/getdata.py: line 7: from: command not found
: command not foundta.py: line 8:
/root/Desktop/getdata.py: line 9: syntax error near unexpected token `('
/root/Desktop/getdata.py: line 9: `dir_path = os.path.dirname(os.path.realpath(_'file__))
Do I need to convert my files to .sh? How would I do that? Is this a bigger problem?
The script for getdata.py is
import os
import tempfile
import paramiko
import time
from pywinauto import Application
from subprocess import Popen, PIPE, STDOUT
dir_path = os.path.dirname(os.path.realpath(__file__))
class Connection(object):
"""Connects and logs into the specified hostname.
Arguments that are not given are guessed from the environment."""
def __init__(self,
host,
username=None,
private_key=None,
password=None,
port=22,
):
self._sftp_live = False
self._sftp = None
if not username:
username = os.environ['LOGNAME']
# Log to a temporary file.
templog = tempfile.mkstemp('.txt', 'ssh-')[1]
paramiko.util.log_to_file(templog)
# Begin the SSH transport.
self._transport = paramiko.Transport((host, port))
self._tranport_live = True
# Authenticate the transport.
if password:
# Using Password.
self._transport.connect(username=username, password=password)
else:
# Use Private Key.
if not private_key:
# Try to use default key.
if os.path.exists(os.path.expanduser('~/.ssh/id_rsa')):
private_key = '~/.ssh/id_rsa'
elif os.path.exists(os.path.expanduser('~/.ssh/id_dsa')):
private_key = '~/.ssh/id_dsa'
else:
raise TypeError(
"You have not specified a password or key.")
private_key_file = os.path.expanduser(private_key)
rsa_key = paramiko.RSAKey.from_private_key_file(private_key_file)
self._transport.connect(username=username, pkey=rsa_key)
def _sftp_connect(self):
"""Establish the SFTP connection."""
if not self._sftp_live:
self._sftp = paramiko.SFTPClient.from_transport(self._transport)
self._sftp_live = True
def get(self, remotepath, localpath=None):
"""Copies a file between the remote host and the local host."""
if not localpath:
localpath = os.path.split(remotepath)[1]
self._sftp_connect()
self._sftp.get(remotepath, localpath)
def put(self, localpath, remotepath=None):
"""Copies a file between the local host and the remote host."""
if not remotepath:
remotepath = os.path.split(localpath)[1]
self._sftp_connect()
self._sftp.put(localpath, remotepath)
def execute(self, command):
"""Execute the given commands on a remote machine."""
channel = self._transport.open_session()
channel.exec_command(command)
output = channel.makefile('rb', -1).readlines()
if output:
return output
else:
return channel.makefile_stderr('rb', -1).readlines()
def update(self):
"""Execute the given commands on a remote machine."""
channel = self._transport.invoke_shell(term='xterm')
channel.exec_command('~/Desktop/update.sh')
output = channel.makefile('rb', -1).readlines()
if output:
return output
else:
return channel.makefile_stderr('rb', -1).readlines()
def close(self):
"""Closes the connection and cleans up."""
# Close SFTP Connection.
if self._sftp_live:
self._sftp.close()
self._sftp_live = False
# Close the SSH Transport.
if self._tranport_live:
self._transport.close()
self._tranport_live = False
def __del__(self):
"""Attempt to clean up if not explicitly closed."""
self.close()
def getData():
"""Create, get, and put delim file when called directly."""
app = Application().start(r"c:\putty.exe trak#10.1.10.70 -pw trak")
app.window_(
title_re=".*trak.*").TypeKeys("/home/trak/Desktop/getdata.sh && exit{ENTER}")
app.window_(title_re=".*trak.*").WaitNot("exists", timeout=120)
trakfile = dir_path + '/storage/trakdelim.txt'
shell = Connection('10.1.10.70', "trak", password="trak")
shell.get('/trak/data/trakdelim.txt', trakfile)
shell.close()
if __name__ == "__main__":
getData()
I appreciate anyone who can help and I can clarify when needed!
A bit of googling showed me what this is:
Someone copied this code and wrote a simple script with it that takes a file (/trak/data/trakdelim.txt) on a remote computer with ip address 10.1.10.70 username trak and password trak and copies it to the storage/trakdelim.txt file. if this is not working for you now then take a tool that allows you to do this manually with such as winSCP and use that instead.
Good luck.
You need to execute it as a python script.
python ~/Desktop/getdata.py
i have read other Stackoverflow threads on this. Those are older posts, i would like to get the latest update.
Is it possible to send multiple commands over single channel in Paramiko ? or is it still not possible ?
If so, is there any other library which can do the same.
Example scenario, automating the Cisco router confi. : User need to first enter "Config t" before entering the other other commands. Its currently not possible in paramiko.
THanks.
if you are planning to use the exec_command() method provided within the paramiko API , you would be limited to send only a single command at a time , as soon as the command has been executed the channel is closed.
The below excerpt from Paramiko API docs .
exec_command(self, command) source code Execute a command on the
server. If the server allows it, the channel will then be directly
connected to the stdin, stdout, and stderr of the command being
executed.
When the command finishes executing, the channel will be closed and
can't be reused. You must open a new channel if you wish to execute
another command.
but since transport is also a form of socket , you can send commands without using the exec_command() method, using barebone socket programming.
Incase you have a defined set of commands then both pexpect and exscript can be used , where you read a set of commands form a file and send them across the channel.
See my answer here or this page
import threading, paramiko
strdata=''
fulldata=''
class ssh:
shell = None
client = None
transport = None
def __init__(self, address, username, password):
print("Connecting to server on ip", str(address) + ".")
self.client = paramiko.client.SSHClient()
self.client.set_missing_host_key_policy(paramiko.client.AutoAddPolicy())
self.client.connect(address, username=username, password=password, look_for_keys=False)
self.transport = paramiko.Transport((address, 22))
self.transport.connect(username=username, password=password)
thread = threading.Thread(target=self.process)
thread.daemon = True
thread.start()
def closeConnection(self):
if(self.client != None):
self.client.close()
self.transport.close()
def openShell(self):
self.shell = self.client.invoke_shell()
def sendShell(self, command):
if(self.shell):
self.shell.send(command + "\n")
else:
print("Shell not opened.")
def process(self):
global strdata, fulldata
while True:
# Print data when available
if self.shell is not None and self.shell.recv_ready():
alldata = self.shell.recv(1024)
while self.shell.recv_ready():
alldata += self.shell.recv(1024)
strdata = strdata + str(alldata)
fulldata = fulldata + str(alldata)
strdata = self.print_lines(strdata) # print all received data except last line
def print_lines(self, data):
last_line = data
if '\n' in data:
lines = data.splitlines()
for i in range(0, len(lines)-1):
print(lines[i])
last_line = lines[len(lines) - 1]
if data.endswith('\n'):
print(last_line)
last_line = ''
return last_line
sshUsername = "SSH USERNAME"
sshPassword = "SSH PASSWORD"
sshServer = "SSH SERVER ADDRESS"
connection = ssh(sshServer, sshUsername, sshPassword)
connection.openShell()
connection.send_shell('cmd1')
connection.send_shell('cmd2')
connection.send_shell('cmd3')
time.sleep(10)
print(strdata) # print the last line of received data
print('==========================')
print(fulldata) # This contains the complete data received.
print('==========================')
connection.close_connection()
Have a look at parallel-ssh:
from pssh.pssh2_client import ParallelSSHClient
cmds = ['my cmd1', 'my cmd2']
hosts = ['myhost']
client = ParallelSSHClient(hosts)
for cmd in cmds:
output = client.run_command(cmd)
# Wait for completion
client.join(output)
Single client, multiple commands over same SSH session and optionally multiple hosts in parallel - also non-blocking.
I find this simple to understand and use. Code provides 2 examples with singlehost and multihost. Also added example where you can login to a second user and continue your commands with that user.
More info can be found in here: https://parallel-ssh.readthedocs.io/en/latest/advanced.html?highlight=channel#interactive-shells
from pssh.clients import SSHClient
from pssh.exceptions import Timeout
from pssh.clients import ParallelSSHClient
from pssh.config import HostConfig
def singleHost():
host_ = "10.3.0.10"
pwd_ = "<pwd>"
pwd_root = "<root pwd>"
user_ = "<user>"
client = SSHClient(host_, user=user_, password=pwd_, timeout=4, num_retries=1)
#####
shell = client.open_shell(read_timeout=2)
shell.run("whoami")
# login as new user example
shell.run("su - root")
shell.stdin.write(pwd_root + "\n")
shell.stdin.flush()
shell.run("pwd")
try:
# Reading Partial Shell Output, with 'timeout' > client.open_shell(read_timeout=2)
for line in shell.stdout:
print(line)
except Timeout:
pass
shell.run("whoami")
shell.run("cd ..")
print(".......")
try:
# Reading Partial Shell Output, with 'timeout' > client.open_shell(read_timeout=2)
for line in shell.stdout:
print(line)
except Timeout:
pass
shell.close()
def multiHost():
pwd_ = "<pwd>"
user_ = "<user>"
workingIP_list = ["10.3.0.10", "10.3.0.10"]
host_config_ = []
# HostConfig is needed one per each 'workingIP_list'
host_config_.append(HostConfig(user=user_, password=pwd_))
host_config_.append(HostConfig(user=user_, password=pwd_))
client_ = ParallelSSHClient(workingIP_list, host_config=host_config_, num_retries=1, timeout=3)
# now you have an open shell
shells = client_.open_shell(read_timeout=2)
command = "pwd"
client_.run_shell_commands(shells, command)
try:
# Reading Partial Shell Output, with 'timeout' > client_.open_shell(read_timeout=2)
for line in shells[0].stdout:
print(line)
except Timeout:
pass
print(".......")
command = "cd repo/"
client_.run_shell_commands(shells, command)
command = "pwd"
client_.run_shell_commands(shells, command)
#Joined on shells are closed and may not run any further commands.
client_.join_shells(shells)
for shell in shells:
for line in shell.stdout:
print(line)
print(shell.exit_code)
if __name__ == '__main__':
print("singleHost example:")
singleHost()
print("multiHost example:")
multiHost()