I'm looking for a solution to check whether or not a specific interface (eth0, wlan0, etc) has internet or not.
My situation is as follows; I have 2 active connections. One ethernet connection that has no internet (eth0) and one Wireless connection (wlan0) that has internet. Both have recieved an LAN IP from their respective DHCP servers.
I have come to the conclusion, but I am very open to suggestions, that the best solution would:
Have a ping command:
ping -I wlan0 -c 3 www.google.com
And have Python pick up or not I am able to reach the destination (check for: "Destination Host Unreachable")
import subprocess
command = ["ping", "-I", "wlan0", "-c", "3", "www.google.com"]
find = "Destination Host Unreachable"
p = subprocess.Popen(command, stdout=subprocess.PIPE)
text = p.stdout.read()
retcode = p.wait()
if find in command:
print "text found"
else:
print "not found"
This however does not yield the best result, and I could really use some help.
Thanks!
The text variable prints out the pint command output, it's just the finding the text inside the print command output that's not working.
Yes because you don't capture stderr, you can redirect stderr to stdout, you can also just call communicate to wait for the process to finish and get the output:
p = subprocess.Popen(command, stdout=subprocess.PIPE,
stderr=subprocess.STDOUT)
out,_ = p.communicate()
You can also just use check_call which will raise an error for any non-zero exit status:
from subprocess import check_call, CalledProcessError, PIPE
def is_reachable(inter, i, add):
command = ["ping", "-I", inter, "-c", i, add]
try:
check_call(command, stdout=PIPE)
return True
except CalledProcessError as e:
print e.message
return False
If you want to only catch a certain error, you can check the return code.
def is_reachable(inter, i, add):
command = ["ping", "-I", inter, "-c", i, add]
try:
check_call(command, stdout=PIPE)
return True
except CalledProcessError as e:
if e.returncode == 1:
return False
raise
Related
So I've been struggling to suppress my terminal output whenever I send a packet. I just want to validate the response (0,2 or else) so my terminal won't get spammed with the standard "ping statistics, packets received, packet loss". How would I go about doing this code-wise? I'm not looking for a terminal / bash "way".
def ping():
hosts = open('hosts.txt', 'r')
for host_ip in hosts:
res = subprocess.call(['ping', '-c', '1', host_ip])
if res == 0:
print "ping to", host_ip, "OK"
elif res == 2:
print "no response from", host_ip
else:
print "ping to", host_ip, "failed!"
I just pinged to google dns servers using python's subprocess.Popen class and it returns nothing to the terminal except the returncode I printed in code
import subprocess
process = subprocess.Popen(['ping','-c' ,'1', '8.8.8.8'], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
stdout, stderr = process.communicate()
returncode = process.returncode
print(returncode)
OUTPUT
0
I am writing a python script to calculate packet loss through ping an IP address using subprocess module in linux. More than one IP address kept in CSV file. It is running fine when the pingable destination are only given.
But throwing an error when the non-pingable IP given in the CSV file and then the script is exiting without checking the other IP address in that CSV file. So I am not able to capture the packet loss for the non-pingable destination which is the main purpose the script.
Please suggest a way forward.
subprocess.check_output(['ping','-c 4',hostname], shell=False,
universal_newlines=True).splitlines()
subprocess.CalledProcessError: Command '['ping', '-c 4', '192.168.134.100']' returned non-zero exit status 1
It is just that subprocess returns an error if your ping has 100% packet loss, destination unreachable or any other problem. What you could do is:
try:
# subprocess code here
except:
# some code here if the destination is not pingable, e.g. print("Destination unreachable..") or something else
pass # You need pass so the script will continue on even after the error
Try this Code:
import subprocess
def systemCommand(Command):
Output = ""
Error = ""
try:
Output = subprocess.check_output(Command,stderr = subprocess.STDOUT,shell='True')
except subprocess.CalledProcessError as e:
#Invalid command raises this exception
Error = e.output
if Output:
Stdout = Output.split("\n")
else:
Stdout = []
if Error:
Stderr = Error.split("\n")
else:
Stderr = []
return (Stdout,Stderr)
#in main
Host = "ip to ping"
NoOfPackets = 2
Timeout = 5000 #in milliseconds
#Command for windows
Command = 'ping -n {0} -w {1} {2}'.format(NoOfPackets,Timeout,Host)
#Command for linux
#Command = 'ping -c {0} -w {1} {2}'.format(NoOfPackets,Timeout,Host)
Stdout,Stderr = systemCommand(Command)
if Stdout:
print("Host [{}] is reachable.".format(Host))
else:
print("Host [{}] is unreachable.".format(Host))
I want to call ping from Python and get the output. I tried the following:
response = os.system("ping "+ "- c")
However, this prints to the console, which I don't want.
PING 10.10.0.100 (10.10.0.100) 56(86) bytes of data.
64 bytes from 10.10.0.100: icmp_seq=1 ttl=63 time=0.713 ms
64 bytes from 10.10.0.100: icmp_seq=2 ttl=63 time=1.15 ms
Is there a way to not print to the console and just get the result?
To get the output of a command, use subprocess.check_output. It raises an error if the command fails, so surround it in a try block.
import subprocess
try:
response = subprocess.check_output(
['ping', '-c', '3', '10.10.0.100'],
stderr=subprocess.STDOUT, # get all output
universal_newlines=True # return string not bytes
)
except subprocess.CalledProcessError:
response = None
To use ping to know whether an address is responding, use its return value, which is 0 for success. subprocess.check_call will raise and error if the return value is not 0. To suppress output, redirect stdout and stderr. With Python 3 you can use subprocess.DEVNULL rather than opening the null file in a block.
import os
import subprocess
with open(os.devnull, 'w') as DEVNULL:
try:
subprocess.check_call(
['ping', '-c', '3', '10.10.0.100'],
stdout=DEVNULL, # suppress output
stderr=DEVNULL
)
is_up = True
except subprocess.CalledProcessError:
is_up = False
In general, use subprocess calls, which, as the docs describe, are intended to replace os.system.
If you only need to check if the ping was successful, look at the status code; ping returns 2 for a failed ping, 0 for a success.
I'd use subprocess.Popen() (and not subprocess.check_call() as that raises an exception when ping reports the host is down, complicating handling). Redirect stdout to a pipe so you can read it from Python:
ipaddress = '198.252.206.140' # guess who
proc = subprocess.Popen(
['ping', '-c', '3', ipaddress],
stdout=subprocess.PIPE)
stdout, stderr = proc.communicate()
if proc.returncode == 0:
print('{} is UP'.format(ipaddress))
print('ping output:')
print(stdout.decode('ASCII'))
You can switch to subprocess.DEVNULL* if you want to ignore the output; use proc.wait() to wait for ping to exit; you can add -q to have ping do less work, as it'll produce less output with that switch:
proc = subprocess.Popen(
['ping', '-q', '-c', '3', ipaddress],
stdout=subprocess.DEVNULL)
proc.wait()
if proc.returncode == 0:
print('{} is UP'.format(ipaddress))
In both cases, proc.returncode can tell you more about why the ping failed, depending on your ping implementation. See man ping for details. On OS X the manpage states:
EXIT STATUS
The ping utility exits with one of the following values:
0 At least one response was heard from the specified host.
2 The transmission was successful but no responses were received.
any other value
An error occurred. These values are defined in <sysexits.h>.
and man sysexits lists further error codes.
The latter form (ignoring the output) can be simplified by using subprocess.call(), which combines the proc.wait() with a proc.returncode return:
status = subprocess.call(
['ping', '-q', '-c', '3', ipaddress],
stdout=subprocess.DEVNULL)
if status == 0:
print('{} is UP'.format(ipaddress))
* subprocess.DEVNULL is new in Python 3.3; use open(os.devnull, 'wb') in it's place in older Python versions, making use of the os.devnull value, e.g.:
status = subprocess.call(
['ping', '-q', '-c', '3', ipaddress],
stdout=open(os.devnull, 'wb'))
I have a function in a python script that basically checks whether a remote server is up or not using ping. If it is not up then it should wait till it is up and only then return. But the script doesn't return if the remote server is down, if the remote server is up then the script returns.
I have tried both subprocess and os.system, I also tried with various parameters in ping command like -c, -w and -W but nothing seems to help. Any ideas on what I might be doing wrong?
Here is the code:
def waitTillUp():
command = "ping -c 1 -W 2 " + remoteServer
response = os.system(command)
if response == 0:
print "UP\n"
else:
print "Down\n"
'''
args = shlex.split(command)
p = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
output, err = p.communicate()
logging.debug("Waiting for the Remote Server to be up")
while "4 packets transmitted, 4 received" not in output:
logging.debug("Waiting for the remoteServer to be up")
p = subprocess.Popen(args, stdout=subprocess.PIPE)
output, err = p.communicate()
'''
Ideally it should loop till it is up but just for the sake of checking whether it is returning or not I have just put an if else condition. When the remote server does actually come up, the script is still stuck and not stopping. Once I hit an enter in the window, it returns. Any suggestions are welcome.
Update# 2
Right now I am just trying to do this, not checking for any response or anything. I just hope to let the program fall through to main and then end of program but it is not even doing that.
def waitTillUp():
command = "ping -c 1 " + Params.storageArray
response = os.system(command)
I am using lot of subprocess.Popen calls one after the other, so is it possible that some buffer is not getting cleared or something of similar sort? Can this be the reason for the weird behavior?
Update# 3
The problem is probably in the reboot call of the remote server before the code that I have pasted. I changed few things and realized that at the function where I am trying to do a reboot, at that point the function is not returning.
This is the complete code. With logging statements I am able to determine that the call for reboot, below marked as the "CULPRIT CALL" is the point where the execution is getting stuck and doesn't proceed till it gets a ENTER key from the user.
def waitTillUp():
command = "ping -c 1 " + remoteServer
response = os.system(command)
def execCmd(op, command):
logging.info("Executing %s operation(command: %s)" %(op, command))
args = shlex.split(command)
sys.stdout.flush()
p = subprocess.Popen(args, stdout=subprocess.PIPE)
output, err = p.communicate()
logging.debug("Output of %s operation: %s" %(op, output))
def install():
execCmd("chmod", "ssh root#" + remoteServer + " chmod +x ~/OS*.bin")
execCmd("reboot", "ssh root#" + remoteServer + " reboot -nf") ### CULPRIT CALL
waitTillUp()
def main():
install()
In python, I am trying to connect thru ssh and play multiple commands one by one.
This code works fine and output is printed out to my screen:
cmd = ['ssh', '-t', '-t', 'user#host']
p = subprocess.Popen(cmd, stdin=subprocess.PIPE)
p.stdin.write('pwd\n')
p.stdin.write('ls -l\n')
p.stdin.write('exit\n')
p.stdin.close()
My problem is when I try to grab each response in a string. I have tried this but the read function is blocking:
cmd = ['ssh', '-t', '-t', 'user#host']
p = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE)
p.stdin.write('pwd\n')
st1 = p.stdout.read()
p.stdin.write('ls -l\n')
st2 = p.stdout.read()
p.stdin.close()
I agree with Alp that it's probably easier to have a library to do the connection logic for you. pexpect is one way to go. The below is an example with paramiko. http://docs.paramiko.org/en/1.13/
import paramiko
host = 'myhost'
port, user, password = '22', 'myuser', 'mypass'
client = paramiko.SSHClient()
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
client.load_system_host_keys()
client.connect(host, port, user, password, timeout=10)
command = 'ls -l'
stdin, stdout, stderr = client.exec_command(command)
errors = stderr.read()
output = stdout.read()
client.close()
The read() call is blocking because, when called with no argument, read() will read from the stream in question until it encounters EOF.
If your use case is as simple as your example code, a cheap workaround is to defer reading from p.stdout until after you close the connection:
cmd = ['ssh', '-t', '-t', 'deploy#pdb0']
p = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE)
p.stdin.write('pwd\n')
p.stdin.write('ls -l\n')
p.stdin.write('exit\n')
p.stdin.close()
outstr = p.stdout.read()
You'll then have to parse outstr to separate the output of the different comamnds. (Looking for occurrences of the remote shell prompt is probably the most straightforward way to do that.)
If you need to read the complete output of one command before sending another, you have several problems. First this can block:
p.stdin.write('pwd\n')
st1 = p.stdout.read()
because the command you write to p.stdin might be buffered. You need to flush the command before looking for output:
p.stdin.write('pwd\n')
p.stdin.flush()
st1 = p.stdout.read()
The read() call will still block, though. What you want to do is call read() with a specified buffer size and read the output in chunks until you encounter the remote shell prompt again. But even then you'll still need to use select to check the status of p.stdout to make sure you don't block.
There's a library called pexpect that implements that logic for you. It'll be much easier to use that (or, even better, pxssh, which specializes pexpect for use over ssh connections), as getting everything right is rather hairy, and different OSes behave somewhat differently in edge cases. (Take a look at pexpect.spawn.read_nonblocking() for an example of how messy it can be.)
Even cleaner, though, would be to use paramiko, which provides a higher level abstraction to doing things over ssh connections. In particular, look at the example usage of the paramiko.client.SSHClient class.
Thanks for both of you for your answers. To keep it simple I have updated my code with:
def getAnswer(p, cmnd):
# send my command
if len(cmnd) > 0:
p.stdin.write(cmnd + '\n')
p.stdin.flush()
# get reply -- until prompt received
st = ""
while True:
char = p.stdout.read(1)
st += char
if char == '>':
return st
cmd = ['ssh', '-t', '-t', 'user#host']
p = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE)
#discard welcome message
getAnswer(p, '')
st1 = getAnswer(p, 'pwd')
st2 = getAnswer(p, 'ls -l')
...
p.stdin.write('exit\n')
p.stdin.flush()
p.stdin.close()
p.stdout.close()
This is not perfect but works fine. To detect a prompt I am simply waiting for a '>' this could be improved by first sending a 'echo $PS1' and build a regexp accordingly.