Unable to store terminal output of subprocess with python - python

My code has two potential outcomes in the terminal: Can't connect RFCOMM socket: Permission denied and Can't connect RFCOMM socket: Host is down. I need to store either result as a string in a variable, but everything I've tried has failed. This is the code that I thought would do it:
from subprocess import check_output
out = check_output(["sudo", "rfcomm", "connect", "0", "AA:BB:CC:DD:EE:FF", "10"])
print "output: %s" % out
Instead I get nothing:
user:~/home $./foo.py
Can't connect RFCOMM socket: Permission denied
output:
Another attempt:
proc = subprocess.Popen(["sudo rfcom connect 0 AA:BB:CC:DD:EE:FF 10"], stdout=subprocess.PIPE, shell=True)
(out, err) = proc.communicate()
print "output: %s" % out, err
This at least gives me something when I print. Unfortunately it's "None" telling me there is no error and not the actual output:
user:~/home $./foo.py
Can't connect RFCOMM socket: Permission denied
output: None
I've already tried this this this this and probably a couple others. I'm sure I'm missing a piece of critical knowledge somewhere. Thanks for any pointers!

rfcomm is apparently writing its output to standard error, yet you are only capturing standard output. To capture both, include stderr=subprocess.STDOUT in the call to check_output:
subprocess.check_output(["sudo", "rfcomm", "connect", "0", "AA:BB:CC:DD:EE:FF", "10"],
stderr=subprocess.STDOUT)

Related

Establish ssh session by giving password using script in python

I have written a below script to do ssh and providing password .But it still waits for password prompt while running . Searched through many such questions on stack overflow, Everyone suggesting to use paramiko or pexpect but I can not use this as this script has to be run by many people on different machines and can not ask everyone to install these libraries first
Looking for a solution without using such libraries
import subprocess
import sys
HOST="lab#xxxx"
COMMAND="pwd"
ssh = subprocess.Popen(["ssh", "%s" % HOST, COMMAND], shell=False, stdout=subprocess.PIPE, stdin = subprocess.PIPE, stderr=subprocess.PIPE)
ssh.stdin.write('lab\n')
ssh.stdin.flush()
result = ssh.stdout.readlines()
if result == []:
error = ssh.stderr.readlines()
print >>sys.stderr, "ERROR: %s" % error
else:
print result
~

connecting to remote host and perform operation

I have requirement to connect to one remote host and perform set of operation using python script like grep for files and check whether DB is running or not .
This what sample code i got
import subprocess
import sys
HOST="yyy03xxx.us.kkk.com"
# Ports are handled in ~/.ssh/config since we use OpenSSH
COMMAND="uname -a"
ssh = subprocess.Popen(["ssh", "%s" % HOST, COMMAND],
shell=False,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
result = ssh.stdout.readlines()
if result == []:
error = ssh.stderr.readlines()
print >>sys.stderr, "ERROR: %s" % error
else:
print result
Please suggest how can i modify this code to multiple operation

How to check if there is a SSH hostname resolution error

I'm using Python to automate copying binaries off a network sensor using scp. I want to add in some error checking and I can't figure out how to reliably check if SSH throws errors, such as a hostname resolution error. I'm currently using .communicate() to collect stdout, and then matching on "ssh" in the error message. The reason I'm checking if err starts with "ssh" is because if no error is thrown, that err variable contains the banner of the sensor it's logging in to, so I don't really have a way to reliably check if err actually has a value or not (If that makes sense). I'm also checking error codes in case a file is not found or some other error is tossed. Is there a better method?
This is the currently working code:
sp = Popen(['scp', '#'.join([self.user, self.sensor]) + ':{0}{1}'.format(self.binPath, self.binName), self.storePath], stdout = PIPE, stderr = PIPE)
data, error = sp.communicate()
if error.startswith("ssh"):
print("ERROR: {}".format(error))
else:
if sp.returncode == 1:
print("ERROR: {} - No such file or directory".format(self.binPath + self.binName))
elif sp.returncode == 0:
self.hashCMP(self.storePath, self.binName, md5Sum)
else:
pass
Would one way around this be to create a test for the domain? For example using something like:
from socket import getaddrinfo
result = getaddrinfo("www.google.com", None)
print result[0][4]
I notice you are using popen - if your OS has nc (netcat) could you maybe run the command:
nc -v <host> <port> #I believe this uses the getaddrinfo under the hood as well ;-)
Thanks,
//P

Python paramiko module using multiple commands

I have a class that creates the connection. I can connect and execute 1 command before the channel is closed. On another system i have i can execute multiple commands and the channel does not close. Obviously its a config issue with the systems i am trying to connect to.
class connect:
newconnection = ''
def __init__(self,username,password):
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
try:
ssh.connect('somehost', username=username,password=password,port=2222,timeout=5)
except:
print "Count not connect"
sys.exit()
self.newconnection = ssh
def con(self):
return self.newconnection
Then i use 'ls' command just to print some output
sshconnection = connect('someuser','somepassword').con()
stdin, stdout, stderr = sshconnection.exec_command("ls -lsa")
print stdout.readlines()
print stdout
stdin, stdout, stderr = sshconnection.exec_command("ls -lsa")
print stdout.readlines()
print stdout
sshconnection.close()
sys.exit()
After the first exec_command runs it prints the expected output of the dir list. When i print stdout after the first exec_command it looks like the channel is closed
<paramiko.ChannelFile from <paramiko.Channel 1 (closed) -> <paramiko.Transport at 0x2400f10L (cipher aes128-ctr, 128 bits) (active; 0 open channel(s))>>>
Like i said on another system i am able to keep running commands and the connection doesn't close. Is there a way i can keep this open? or a better way i can see the reason why it closes?
edit: So it looks like you can only run 1 command per SSHClient.exec_command... so i decided to get_transport().open_session() and then run a command. The first one always works. The second one always fails and the scripts just hangs
With just paramiko after the exec_command executes the channel is closed and the ssh returns an auth prompt.
Seems its not possible with just paramiko, try fabric or another tool.
** fabric did not work out too.
Please see the following referece as it provides a way to do this in Paramiko:
How do you execute multiple commands in a single session in Paramiko? (Python)
it's possible with netmiko (tested on windows).
this example is written for connecting to cisco devices but the principle is adaptable for others as well.
import netmiko
from netmiko import ConnectHandler
import json
def connect_enable_silent(ip_address,ios_command):
with open ("credentials.txt") as line:
line_1 = json.load(line)
for k,v in line_1.items():
router=(k,v)
try:
ssh = ConnectHandler(**router[1],device_type="cisco_ios",ip=ip_address)
ssh.enable()
except netmiko.ssh_exception.NetMikoAuthenticationException:
#incorrect credentials
continue
except netmiko.ssh_exception.NetMikoTimeoutException:
#oddly enough if it can log in but not able to authenticate to enable mode the ssh.enable() command does not give an authentication error
#but a time-out error instead
try:
ssh = ConnectHandler(username = router[1]['username'],password = router[1]['password'],device_type="cisco_ios", ip=ip_address)
except netmiko.ssh_exception.NetMikoTimeoutException:
# connection timed out (ssh not enabled on device, try telnet)
continue
except Exception:
continue
else:
output = ssh.send_command(ios_command)
ssh.disconnect()
if "at '^' marker." in output:
#trying to run a command that requires enble mode but not authenticated to enable mode
continue
return output
except Exception:
continue
else:
output = ssh.send_command(ios_command)
ssh.disconnect()
return output
output = connect_enable_silent(ip_address,ios_command)
for line in output.split('\n'):
print(line)
Credentials text is meant to store different credentials in case you are planning to call this function to access multiple devices and not all of them using the same credentials. It is in the format:
{"credentials_1":{"username":"username_1","password":"password_1","secret":"secret_1"},
"credentials_2":{"username":"username_2","password":"password_2","secret":"secret_2"},
"credentials_3": {"username": "username_3", "password": "password_3"}
}
The exceptions can be changed to do different things, in my case i just needed it to not return an error and continue trying the next set, which is why most exceptions are silenced.

Python Subprocess returncode - different results

I came to run a script on a production box, and it failed in one of it's first checks. I've narrowed it down to the fact my "ping" check (invoked by subprocess) is returning a non-zero result.
Here's the code in it's simplest form:
import subprocess
import sys
ip="127.0.0.1"
ping = subprocess.Popen(["ping", "-c", "2", "-w", "1", ip], shell=False)
ping.wait()
if ping.returncode != 0:
print ping.returncode, "ERROR: failed to ping host. Please check."
sys.exit(1)
else:
print "OK"
Both servers are CentOS 5.5 & Python 2.4.3, but one works and one doesn't!
From the command line a manual ping (of 127.0.0.1) returns 0 in both cases. Why is their a difference when using the subprocess module in python?
Cheers.

Categories

Resources