Executing Interactive SSH Command via Python script - python

I am trying to automate to collect the logs from the Cisco Call Manager via CLI by using the from paramiko_expect import SSHClientInteraction where I am not able to send the interactive command to the server.
While trying to download the logs, it will ask information like SFTP IP address, username, password and directory which needs to send an interactive command.
whenever the code runs, it stops at the interactive command section where its not sending the command to the server because of which python script stops here. need to know is there any other way to code these requirements.
for example
Below section is interactive shell where I have to type y/xx.xx.xx.xx/22/User ID/Password/Directory but I can't do the same.
I need help here.. to send the command
+++++++++++++++++++++++++++++++++
Would you like to proceed [y/n]? y
SFTP server IP: xx.xx.xx.xx
SFTP server port [22]: 22
User ID: *****
Password: *****
Download directory: /
+++++++++++++++++++++++++++++++++
Command Line Interface is starting up, please wait ...
Welcome to the Platform Command Line Interface
VMware Installation:
4 vCPU: Intel(R) Xeon(R) Platinum 8180 CPU # 2.50GHz
Disk 1: 110GB, Partitions aligned
6144 Mbytes RAM
admin:file get activelog /syslog/AlternateSyslog
Please wait while the system is gathering files info ...
Get file: active/syslog/AlternateSyslog
done.
Sub-directories were not traversed.
Number of files affected: 5
Total size in Bytes: 23354752
Total size in Kbytes: 22807.375
Would you like to proceed [y/n]? y
SFTP server IP: xx.xx.xx.xx
SFTP server port [22]:
User ID: *****
Password: *****
Download directory: /
The authenticity of host 'xx.xx.xx.xx (xx.xx.xx.xx)' can't be established.
Are you sure you want to continue connecting (yes/no)? yes
.....
Transfer completed.
admin:
I am able to get the show command output but not able to download the logs.
#!/usr/bin/python
# PSFL license
# Importing SSHClientInteraction from paramiko
import paramiko
from paramiko_expect import SSHClientInteraction
import threading
# Specify connection info for each node in square brackets: ["IP ADDRESS", "USERNAME", "PASSWORD"]
connection = [["xx.xx.xx.xx", "userid", "password"]]
# Define function which is responsible for opening SSH connection and running specified commands
def cucm(ip, username, password):
sshsession = paramiko.SSHClient()
sshsession.set_missing_host_key_policy(paramiko.AutoAddPolicy())
sshsession.connect(ip, username=username, password=password)
# "display=True" is just to show you what script does in real time. While in production you can set it to False
interact = SSHClientInteraction(ssh, timeout=600, display=True)
# program will wait till session is established and CUCM returns admin prompt
interact.expect('admin:')
# program runs show status command
interact.send('show status')
# program waits for show status command to finish (this happen when CUCM returns admin prompt)
interact.except('admin:')
# program sends syslog to download the file
interact.send('file get activelog /syslog/AlternateSyslog')
if interact.last_match == 'Would you like to proceed [y/n]? ': # program matches prompted command by using if command and will send interact command to it.
interact.send('y')
if interact.last_match == 'SFTP server IP:':
interact.send('xx.xx.xx.xx')
if interact.last_match == 'SFTP server port [22]:':
interact.send('22')
if interact.last_match == 'User ID:':
interact.send('userid')
if interact.last_match == 'Password:':
interact.send('password')
if interact.last_match == 'Download directory:':
interact.send('/')
interact.expect('admin:')
output = interact.current_output_clean # program saves output of show status command to the "output" variable
sshsession.close()
# Run loop which will open separate thread for each node specified in the connection list. This targets "session" function defined at the beginning
for i in connection:
t = threading.Thread(target = cucm, args = (i[0], i[1], i[2]))
t.daemon = True
t.start()
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Below is the output for the python script.
there is no error message but it stops at Would you like to proceed [y/n]? here
Command Line Interface is starting up, please wait ...
Welcome to the Platform Command Line Interface
VMware Installation:
4 vCPU: Intel(R) Xeon(R) Platinum 8180 CPU # 2.50GHz
Disk 1: 110GB, Partitions aligned
6144 Mbytes RAM
admin:file get activelog /syslog/AlternateSyslog
Please wait while the system is gathering files info ...
Get file: active/syslog/AlternateSyslog
done.
Sub-directories were not traversed.
Number of files affected: 1
Total size in Bytes: 2261400
Total size in Kbytes: 2208.3984
Would you like to proceed [y/n]?

You could try adding the global configuration command "file prompt quiet" at the beginning of your program before any other commands are sent. This will suppress any yes/no questions and auto them to the default. Just make sure that at the end of the code you turn it back off to prevent any later nasty surprises using "file prompt alert".
This works in most Cisco IOS platforms, if the command is different in CUCM I'm sure there will be an equivalent to do the same thing.

maybe you already sorted this out, but I see, that you have there one small type, which could stop that script of moving forward:
you have there:
interact.except('admin:')
instead of:
interact.expect('admin:')

Related

Issue with capturing Password: prompt on remote device

Fabric not seeing the Password: prompt for remote device (Aruba Mobility Master) over SSH.
The script I wrote is using fabric2 and Python3 to login to a remote network device, and running a command to SCP a file from this device to another device. After running the SCP command the device asks for password. This prompt is visible when running over a normal SSH client, but not visible when running with fabric.
I have tested with pty=False and pty=True
The script doesn't hang like its waiting for input either. It just continues and the SCP fails with incorrect password.
The password prompt is a bit special in that it will echo back characters with stars (*) instead of not echoing anything at all.
The network device does not provide a normal bash shell. Instead its a vendor specific shell (Aruba/HPE). The device is "Aruba Mobility Master"
from invoke import Responder
scppass = Responder(
pattern=r'Password:',
response='MyPassword\n',
)
connect_kwargs = {"password": "LoginPassword"}
c = Connection(host="1.2.3.4", user="username", connect_kwargs=connect_kwargs)
# Have tried with pty=False and pty=True
c.run("copy flash: configbackup.tar.gz scp: 2.3.4.5 username /PATH/configbackup.tar.gz", pty=True, watchers=[scppass])
This is how it looks when run from an interactive SSH session
Password:*********************
Secure file copy:
Press 'q' to abort.
....
File uploaded successfully
This is the output from fabric
Secure file copy:
Press 'q' to abort.
............
Error copying file:
Permission denied: wrong username or password
Also tried with
ssh username#1.2.3.4 "copy flash: nothng scp: 2.3.4.5 user /something/asd" >out 2>err
ssh -t username#1.2.3.4 "copy flash: nothng scp: 2.3.4.5 user /something/asd" >out 2>err
Neither of these capture the "Password:" either in either the stdout or stderr file.

How can I output/print "proof" that the server is being rebooted using the script I've written?

Essentially I wrote a script that reboots a server using python and an SSH library called paramiko. My script runs as it should, but I don't know if it is actually rebooting the server because the server is not on site in the office. Is there a way where I can print and output "proof" that the server is actually being rebooted ? I am a little new to using python to give commands to network devices using SSH.
I did actually run my code and it runs as it should, but I have not tested to see if a server is actually turning on and off.
There is no need to copy and paste all of my code, but there are two functions that are extremely important:
def connectToSSH(deviceIP, deviceUsername, devicePassword):
ssh_port = 22
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect(deviceIP, ssh_port, deviceUsername, devicePassword)
time.sleep(5)
return ssh
def reboot_server(ssh):
prompt = raw_input('Are you sure you want to reboot this server ?')
if prompt.lower() == 'y' or prompt.lower() == 'n':
print('Proceeding to reboot the switch\n')
else:
print('Proceeding to exit the program\n')
sys.exit(-1)
channel = ssh.invoke_shell()
ssh.exec_command("/sbin/reboot -f > /dev/null 2>&1 &") # executes command to reboot server , is this the right command ? I found this on another stackOverflow post ?
channel.close()
print("Please wait for server to be rebooted")
I am receiving no compile errors but I want to be sure that the command:
ssh.exec_command("/sbin/reboot -f > /dev/null 2>&1 &")
is actually rebooting the server. If it is, is there a way I can print/output proof that it is being rebooted ? If so, how do I go about doing that ?

mount via paramiko fails "No such file or directory"

i am using paramiko of python to manipulate access remote linux machine. My command "mount device dir" is failing with " No such file or directory", even though exact the same command succeeds once i use it remotely (connected via ssh, not via paramiko).
I have tried to vary /etc/fstab to some values, again, same situation. Once i type it via ssh - ok, the same command via paramiko - above error message.
Any ideas?
example on command (changed minimally from origin):
import paramiko
self.ssh = paramiko.SSHClient()
self.ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
self.ssh.connect('192.168.1.1', username='root', password='passwd')
stdin, stdout, stderr = self.ssh.exec_command("/bin/mount /dev/sda1")
gives me an error:
mount /dev/sda1 failed: mount: mounting /dev/sda1 on /media/card failed: No such file or directory
contents from /etc/fstab:
/dev/sda1 /media/card vfat fmask=0000,dmask=0000 0 0
of course, /media/card directory exists. again, i can use above command manually via ssh and it works as expected.
update.
meanwhile i tried fabric library of python (built on paramiko), exactly as described in Python - How do I authenticate SSH connection with Fabric module?
c = fabric.Connection(host = '192.168.1.1', user = "root", connect_kwargs={'password': 'passwd'})
c.run("/bin/mount /dev/sda1")
giving me exactly the same error message as with paramiko directly.
update2. well, as a matter of working around, i mounting drive using direct ssh call, as suggested below in comments. after i do in code whatever necessary, i try to unmount drive using "normal" paramiko call:
self.ssh.exec_command("/bin/umount /dev/sda1")
and it works. so now i am completely lost, mount as above is failing, but unmount is working. this is real strange..
update3. i have tried to extra set LD_LIBRARY_PATH to location of mount's libraries, it needs both libm.so.6 and libc.so.6, both located in /lib like:
self.ssh.exec_command("export LD_LIBRARY_PATH=/lib:/usr/lib && /bin/mount /dev/sda1")
yet no success again.
I was able to get this to work (first draft. Also, I am new to python). Anyway, here is a snip of my code.
The biggest hang-up for me was that it seems as though there is a 4->1 requirement for back slashes in the windows hostname.
Make sure you have a share from the windows PC first. My computer/share name in this case is "COMP_NAME/SHARE_NAME"
The username/password provided are your window creds for accessing the share.
import sys
import paramiko
import constant
### START ###############################################################################
# connect to a GW device
# GW: hostname to connect to
# return: client connection object
def connectToClient(GW):
try:
client = paramiko.SSHClient()
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
client.connect(GW, username=constant.GW_USER, password=constant.GW_PASS)
except:
print("Unexpected error:", sys.exc_info()[0])
return None
return client
### END ################################################################################
### START ###############################################################################
# execute a command on the remote device
# client: client connection object to the GW
# cmd: the command to execute
# eg. 'ls -l'
# return: nothing (TODO: maybe return error info)
def exec(client, cmd):
stdin, stdout, stderr = client.exec_command(cmd)
for line in stdout:
print(line.strip('\n'))
#for line in stderr:
# print(line.strip('\n'))
return
### END #################################################################################
# other stuff
# .
# .
# .
##########################################
# Start - upload the self extracting file to the GW
##########################################
#create the mount point
exec(client, "sudo mkdir /mnt/remote_files")
#mount the source directory (4 to 1 for the back slash chars in the UNC address ...)
exec(client, "sudo mount -t cifs -o username=oxxxxxxp,password=cxxxxxxxxx0 \\\\\\\\COMP_NAME\\\\SHARE_NAME /mnt/remote_files")
#copy the script file
exec(client, "cp /mnt/remote_files/selfextract.bsx rtls/scripts/selfextract.bsx")
#unmount the remote source
exec(client, "sudo umount /mnt/remote_files")
##########################################
# Done - upload the self extracting file to the GW
##########################################
# other stuff
# .
# .
# .
Hope this helps someone..
Pat

python sockets application not functioning as expected from terminal

I'm following a book I purchased called 'Black Hat Python' but have run into an issue I cannot seem to resolve.
The book so far has had the reader create a few python applications: a command line tool to send/receive data, execute commands remotely and a TCP proxy client that redirects a connection via specified host/port.
The issue is that when I launch these from the terminal, I receive no output and the terminal waits for my input with a screen grab type cursor. It awaits for me to 'grab' an image or part of the screen 3 times and then fails. I then have some image files save to my Home folder named, 'getopt', 'socket', 'subprocess', 'threading' and 'sys'. The output I get from the terminal after 'grabbing' the screen 3 times is:
root#c0ff33:~# ./1proxy.py 127.0.0.1 21 ftpserver.ftp 21 True
./1proxy.py: line 5: syntax error near unexpected token `('
./1proxy.py: line 5: `def server_loop(local_host, local_port, remote_host, remote_port, receive_first):
However, when I run this in my IDE client, it runs fine when I pass it the same arguments. The connection is initiated and awaits the connection to the remote host. The output is then correct and the proxy client waits for a connection via localhost on port 21:
[*] Listening on 127.0.0.1:21
[==>] Receive incoming connection from 127.0.0.1:49475
Does anyone know why this is happening? Why can I not execute this from the terminal with the same results?
The arguments I am passing are:
./myproxy.py 127.0.0.1 21 ftpserver.ftp 21 True
127.0.0.1 = localhost
21 = local port
ftpserver.ftp = remote host
21 = remote port
True = receive first
That could happen because your shell tries to pass your script to BASH to execute. BASH will see lots of errors in your code. Instead of typing ./code.py you need to run python code.py or add #!/path/to/python in the beginning of your script.

Automating SSH using Python

I have this 30 virtual machines and I am doing everything manually right now which is a kind of trouble for me. I am trying now to write a script so I can connect to them all automatically and do my desired task. I made a flow diagram of what I need to do. Can anybody just give me some hints on how will i achieve this task programatically. I am attaching the flow diagram.
Thanks in Advance.
Please Right Click On Image and Click View Image to See the Flow Diagram.
Reading a text file and getting the data is trivial:
with open('host.txt', 'r') as inf:
lines = inf.readlines()
hostlist = [ln.split() for ln in lines]
Now hostlist should be a list of lists;
[['192.168.0.23', 'root', 'secret'], ['192.168.0.24', 'root', 'secret2'] ...
But your list shouldn't have to contain more than the hostnames. IP adresses can be gotten from DNS that you have to configure anyway, and ssh can login without passwords if configured correctly.
Putting the passwords for all your virtual hosts in a plain text file has security concerns. If you want to go that route, make sure to restrict access to that file!
You can use subprocess to execute commands. I would suggest using rsync to push the desired files to the virtual machines. That minimizes network traffic. And you can deploy directly from filesystem to filesystem without having to roll a tarball. It can be as simple as
status = subprocess.check_output(['rsync', '-av', localdir, remotedir])
Where localdir is the directory where the files for the virtual machine in question are stored (it should end with a '/'), and 'remotedir' is the hostname::directory on the virtual machine where the data should land (this should not end with a '/').
For executing commands remotely, ssh is the way to go. Configure that for passwordless login, using ssh's authorized_keys file on each remote host. Then you don't need to put passwords in your list of hosts.
Fabric is best solution for you. Fabric based on paramiko ( which based on libssh2), it makes very easy to work with commands on remote host and provides function to upload and download fiels from remote host.
Here it is http://docs.fabfile.org/en/1.5/
Docs about put function here
I don't get your question in the flow diagram, however you can use paramiko as suggested and I have a large number of background utilities written on top of paramiko which enables support people to monitor remote web servers on the browser. Snippet below,
client = paramiko.SSHClient()
client.set_missing_host_key_policy( paramiko.AutoAddPolicy() )
client.load_system_host_keys()
client.connect( '192.168.100.1', port=4001, username='monitor', password='XXXX' )
cmds = [ "sed -i 's/\/bin\/date -u/\/bin\/date/g' /etc/cron.hourly/reboot" ]
for cmd in cmds:
if __DEBUG_MODE__:
print 'Executing..... ' + cmd
stdin, stdout, stderr = client.exec_command( cmd )
Also if you want to push files below is the snippet,
def setupSFTPClient(self, ip_add):
print 'Setting SFTP client: ' + ip_add
tb = 'Finished SFTP-ing. '
try:
client = paramiko.SSHClient()
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
client.load_system_host_keys()
client.connect(ip_add, port=4001, username='monitor', password='XXXX')
sftp_client = client.open_sftp()
# NB you need the filename for remote path otherwise
# paramiko barfs with IOError: Failure
sftp_client.put( '/home/projects/portal_release.tgz', '/var/ND/portal_release.tgz' )
sftp_client.put( '/home/projects/portal_installer.sh', '/var/ND/portal_installer.sh' )
sftp_client.close()
except Exception, e:
print e
tb = traceback.format_exc()
finally:
print tb
client.close()

Categories