How can I evaluate the return of ping command used on subprocess.call(), by having a value of True or False like in the last "if" statement ?
Here is the code:
import subprocess
from openpyxl import load_workbook
from openpyxl import worksheet
_list_test = []
def ping_rng():
wb = load_workbook(filename="IP_gav.xlsx")
ws = wb["172.16.7.X"]
i = 0
for IP_ in range(2,258):
# Get correct cell value
cell_ = ws.cell(row=IP_, column=1).value
_list_test.append(cell_)
# Construct and execute "ping" command
cmd_param = "-n"
command = ['ping', cmd_param, '1', str(_list_test[i])]
response = subprocess.call(command)
print(response) # Just to check the value
# Check the "response"
if response == True:
print("Is up.")
elif response == False:
print("Is down.")
else: print("Nothing Good")
i = i + 1
ping_rng()
The code is working as it should, by iterating on a range of IP addresses (which it get from a XLSX file) and by pinging the single IP address like so:
ping 172.16.7.0 -n 1
As a further attempt, I've found different posts about verifying if subprocess.check_output() is True or False, but this didn't worked for me since it returns the string of ping command in "cmd style", and that is why I've opted for subprocess.call() which returns the state of the command.
Tests:
In the code above, I printed the value of "response" variable by using the 2 different methods:
With subprocess.call() the return is '0' in any cases (so return False in the last "if" statement)
or
With subprocess.check_output() the return is the ping command itself in "cmd style" (return "Nothing Good" in the last "if" statement)
ping will exit with 0 as an exit code if it ran successfully. Given that you seem to want to handle error codes in a generic way, you could keep things simple:
import subprocess
def ping_test(ip):
cmd = ["ping","-n","1",ip]
response = subprocess.call(cmd, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
if response == 0:
print(f"{ip} ping was successful!")
return
print(f"{ip} ping was not successful.")
ping_test("127.0.0.1")
ping_test("300.0.0.0")
prints:
#127.0.0.1 ping was successful!
#300.0.0.0 ping was not successful.
Related
I'm creating a Python program to monitor the processes on a server once an hour, to see if it can return the PID. To do this, I made a function that uses subprocess to call pgrep -f on any name submitted to it. If it returns a process, the function evaluates to true; otherwise, it returns false.
import subprocess
import psutil
def check_essentials(name):
child = subprocess.Popen(['pgrep', '-f', name], stdout=subprocess.PIPE, shell=False)
response = child.communicate()[0]
pid = response.split()
if len(pid) == 0:
print("unable to find PID")
return False
else:
print("PID is %s" % pid)
return True
essentialApps = ['ProfileService','aflaf']
sendEmail=False
for x in essentialApps:
check_essentials(x)
if check_essentials == False:
print("Unable to find PID for %s. Sending email alert" % x)
sendEmail = True
else:
print("Found PID for %s" % x)
I then set up a for loop to have it iterate through a list of process names(essentialApps) and see if it can return anything for them. If not, sendEmail is set to true.
In testing this, however, I'm finding that the else statement is always being called, regardless of whether or not the app exists. When I call this program (python alert.py), I get the following output:
PID is [b'11111']
Found PID for ProfileService
unable to find PID #This is expected
Found PID for aflaf #This should be "Unable to find PID for aflaf"
I'm sure it is something simple, but can anyone tell me why it is not evaluating check_essential correctly?
Also, is there anyway to do this with psutil? I'm reading that this should be used over subprocess, but I'm not able to find anyway to specifically mimic pgrep -f name or ps -aux | grep name. Thats important, as I have multiple Java applications running on the machine, and the program name that psutil seemed to see was always 'java', not 'ProfileService'.
You're not using the result of the function, you're checking if the check_essentials function itself is False.
Which it's not, because it's a function.
You need to you the result of check_essentials in your condition, check_essentials is always True, because it is a Python object:
for x in essentialApps:
check_result = check_essentials(x)
if check_result == False:
Dollar question mark ($?) is used to find the return value of the last executed command and I want to use it in my script but it does not work.
python version : 3.7
Library : subprocess
I searched the answer but I can't find the suit answer in python.
I tried the following code, but it doesn't work :
#!/usr/bin/python
import subprocess
subprocess.call(["ls","-l"])
if $? == 0 :
print("is ok\n")
subprocess.call will return the code and you can store it inside variable:
import subprocess
rv = subprocess.call(["ls","-l"]) # <-- result of the call is stored inside `rv` variable
if rv == 0 : # <-- check the variable
print("is ok") # <-- no need to put additional '\n' to print statement
Prints:
... the result of `ls -l`
is ok
call returns an object with a returncode attribute you can check.
result = subprocess.call(["ls", "-l"])
if result.returncode == 0:
print("is ok")
I have pexpect working, but I am having problems printing the output back from it. In my test script below, it creates the ssh connection, and then sends a sudo su -, then my password, and then sends a line that would require sudo access to do (I have also added p.interact() a few times to make sure it is at root). The problem I am having, is with returning the output of the commands I run. In the end I am wanting to run some top commands, and some du -h, and other(much more complex) space commands. But currently when it tries to print p.before, I get:
Traceback (most recent call last):
File "./ssh.py", line 37, in <module>
print p.before()
TypeError: 'str' object is not callable
Here is the script I am working from(edited to remove my pass and such)
#!/usr/bin/env python
import pexpect
import struct, fcntl, os, sys, signal
def sigwinch_passthrough (sig, data):
# Check for buggy platforms (see pexpect.setwinsize()).
if 'TIOCGWINSZ' in dir(termios):
TIOCGWINSZ = termios.TIOCGWINSZ
else:
TIOCGWINSZ = 1074295912 # assume
s = struct.pack ("HHHH", 0, 0, 0, 0)
a = struct.unpack ('HHHH', fcntl.ioctl(sys.stdout.fileno(), TIOCGWINSZ , s))
global global_pexpect_instance
global_pexpect_instance.setwinsize(a[0],a[1])
ssh_newkey = 'Are you sure you want to continue connecting'
p=pexpect.spawn('ssh user#localhost')
i=p.expect([ssh_newkey,'password:',pexpect.EOF,pexpect.TIMEOUT],1)
if i==0:
print "I say yes"
p.sendline('yes')
i=p.expect([ssh_newkey,'password:',pexpect.EOF])
if i==1:
print "I give password",
p.sendline("mypassword")
elif i==2:
print "I either got key or connection timeout"
pass
elif i==3: #timeout
pass
global global_pexpect_instance
global_pexpect_instance = p
p.sendline("sudo su -")
p.sendline("mypasswd")
p.sendline("mkdir /home/user/test")
print p.before
I am working off of this link: http://linux.byexamples.com/archives/346/python-how-to-access-ssh-with-pexpect/
Any help is much appreciated.
EDIT: As Armin Rigo pointed out below. I was calling to p.before as a function like p.before(). Stupid mistake on my part, as this explains why I was getting this error today, and not yesterday when I was trying this. After making that change to my script, and modifying the command being sent, print p.before, and no output is returned. Any other ways to return output from a sendline() command?
Use logfile, that logfile is store all output in terminal.use that example code:-
child = pexpect.spawn("ssh user#localhost")
child.logfile = open("/tmp/mylog", "w")
child.expect(".*assword:")
child.send("guest\r")
child.expect(".*\$ ")
child.sendline("python -V\r")
open the log file and see everything in terminals event
To fetch the complete output after sendline use child.read()
e.g.
cmd_resp = pexpect.spawnu(cmd) # for execution of the command
str_to_search = 'Please Enter The Password'
cmd_resp.sendline('yes') # for sending the input 'yes'
resp = cmd_resp.expect([str_to_search, 'password:', EOF], timeout=30) # fetch the output status
if resp == 1:
cmd_resp.sendline(password)
resp = cmd_resp.expect([str_to_search, 'outputString:', EOF], timeout=30)
print(cmd_resp.read()) # to fetch the complete output log
p.before is a string - not a function. To see the output you have to write
print p.before.
Hope this might help you
I'm using Python/Pexpect to spawn an SSH session to multiple routers. The code will work for one router but then the output of session.before will get out of sync with some routers so that it will return the output from a previous sendline. This seems particularly the case when sending a blank line (sendline()). Anyone got any ideas? Any insight would be really appreciated.
Below is a sample of what I'm seeing:
ssh_session.sendline('sh version')
while (iresult==2):
iresult = ssh_session.expect(['>','#','--More--'],timeout=SESSION_TIMEOUT)
debug_print("execute_1 " + str(iresult))
debug_print("execute_bef " + ssh_session.before)
debug_print("execute_af " + ssh_session.after)
thisoutput = ssh_session.before
output += thisoutput
if(iresult==2):
debug_print("exec MORE")
ssh_session.send(" ")
else:
debug_print("exec: end loop")
for cmd in config_commands:
debug_print("------------------------------------------------\n")
debug_print ("running command " + cmd.strip() + "\n")
iresult=2
ssh_session.sendline(cmd.strip())
while (iresult==2):
iresult = ssh_session.expect([prompt+">",prompt+"#"," --More-- "],timeout=SESSION_TIMEOUT)
thisoutput = ssh_session.before
debug_print("execute_1 " + str(iresult))
debug_print("execute_af " + ssh_session.after)
debug_print("execute_bef " + thisoutput)
thisoutput = ssh_session.before
output += thisoutput
if(iresult==2):
debug_print("exec MORE")
ssh_session.send(" ")
else:
debug_print("exec: end loop")
I get this:
logged in
exec: sh version
execute_1 1
execute_bef
R9
execute_af #
exec: end loop
------------------------------------------------
running command config t
execute_1 1
execute_af #
execute_bef sh version
Cisco IOS Software, 1841 Software (C1841-IPBASEK9-M), Version 15.1(4)M4, RELEASE SOFTWARE (fc1)
Technical Support: http://www.cisco.com/techsupport...
I've run into this before with pexpect (and I'm trying to remember how I worked around it).
You can re-synchronize with the terminal session by sending a return and then expecting for the prompt in a loop. When the expect times out then you know that you are synchronized.
The root cause is probably that you are either:
Calling send without a match expect (because you don't care about the output)
Running a command that produces output but expecting for a pattern in the middle of that output and then not to next prompt that is at end of the output. One way to deal with this is to change your expect pattern to "(.+)PROMPT" - this will expect until the next prompt and capture all the output of the command sent (which you can parse in the next step).
I faced a similar problem. I tried waiting for the command to be printed on the screen and the sending enter.
I you want to execute say command 'cmd', then you do:
session.send(cmd)
index = session.expect([cmd, pexpect.TIMEOUT], 1)
session.send('\n')
index = session.expect([whatever you expect])
Worked for me.
I'm not sure this is the root of your problem, but it may be worth a try.
Something I've run into is that when you spawn a session that starts with or lands you in a shell, you have to deal with quirks of the TERM type (vt220, color-xterm, etc.). You will see characters used to move the cursor or change colors. The problem is almost guaranteed to show up with the prompt; the string you are looking for to identify the prompt appears twice because of how color changes are handled (the prompt is sent, then codes to backspace, change the color, then the prompt is sent again... but expect sees both instances of the prompt).
Here's something that handles this, guaranteed to be ugly, hacky, not very Pythonic, and functional:
import pexpect
# wait_for_prompt: handle terminal prompt craziness
# returns either the pexpect.before contents that occurred before the
# first sighting of the prompt, or returns False if we had a timeout
#
def wait_for_prompt(session, wait_for_this, wait_timeout=30):
status = session.expect([wait_for_this, pexpect.TIMEOUT, pexpect.EOF], timeout=wait_timeout)
if status != 0:
print 'ERROR : timeout waiting for "' + wait_for_this + '"'
return False
before = session.before # this is what we will want to return
# now look for and handle any additional sightings of the prompt
while True:
try:
session.expect(wait_for_this, timeout=0.1)
except:
# we expect a timeout here. All is normal. Move along, Citizen.
break # get out of the while loop
return before
s = pexpect.spawn('ssh me#myserver.local')
s.expect('password') # yes, we assume that the SSH key is already there
# and that we will successfully connect. I'm bad.
s.sendline('mypasswordisverysecure') # Also assuming the right password
prompt = 'me$'
wait_for_prompt(s, prompt)
s.sendline('df -h') # how full are my disks?
results = wait_for_prompt(s, prompt)
if results:
print results
sys.exit(0)
else:
print 'Misery. You lose.'
sys.exit(1)
I know this is an old thread, but I didn't find much about this online and I just got through making my own quick-and-dirty workaround for this. I'm also using pexpect to run through a list of network devices and record statistics and so forth, and my pexpect.spawn.before will also get out of sync sometimes. This happens very often on the faster, more modern devices for some reason.
My solution was to write an empty carriage return between each command, and check the len() of the .before variable. If it's too small, it means it only captured the prompt, which means it must be at least one command behind the actual ssh session. If that's the case, the program sends another empty line to move the actual data that I want into the .before variable:
def new_line(this, iteration):
if iteration > 4:
return data
else:
iteration+=1
this.expect(":")
this.sendline(" \r")
data = this.before
if len(data) < 50:
# The numer 50 was chosen because it should be longer than just the hostname and prompt of the device, but shorter than any actual output
data = new_line(this, iteration)
return data
def login(hostname):
this = pexpect.spawn("ssh %s" % hostname)
stop = this.expect([pexpect.TIMEOUT,pexpect.EOF,":"], timeout=20)
if stop == 2:
try:
this.sendline("\r")
this.expect(":")
this.sendline("show version\r")
version = new_line(this,0)
this.expect(":")
this.sendline("quit\r")
return version
except:
print 'failed to execute commands'
this.kill(0)
else:
print 'failed to login'
this.kill(0)
I accomplish this by a recursive command that will call itself until the .before variable finally captures the command's output, or until it calls itself 5 times, in which case it simply gives up.
Based on Chapter 12 of the OTP in Action book and Cesarini's book I wrote this Erlang code:
Erlang:
p(Param) ->
?DBG("Starting~n", []),
Cmd = "python test.py",
Port = open_port({spawn,Cmd}, [stream,{line, 1024}, exit_status]),
?DBG("Opened the port: ~w~n", [Port]),
Payload = term_to_binary(list_to_binary(integer_to_list(Param))),
erlang:port_command(Port, Payload),
?DBG("Sent command to port: ~w~n", [Payload]),
?DBG("Ready to receive results for command: ~w~n", [Payload]),
receive
{Port, {data, Data}} ->
?DBG("Received data: ~w~n", [Data]),
{result, Text} = binary_to_term(Data),
Blah = binary_to_list(Text),
io:format("~p~n", [Blah]);
Other ->
io:format("Unexpected data: ~p~n", [Other])
end.
Python:
import sys
def main():
while True:
line = sys.stdin.readline().strip()
if line == "stop-good":
return 0
elif line == "stop-bad":
return 1
sys.stdout.write("Python got ")
sys.stdout.write(line)
sys.stdout.write("\n")
sys.stdout.flush()
if __name__ == "__main__":
sys.exit(main())
The Erlang code suspends at the recieve clause - it never gets any message.
I have also checked Python from a regular Linux shell - it prints out every user input (1 - "Python got 1").
Where is the mistake here? Why doesn't my Erlang code get anything back?
There are two points:
make sure that Python does not buffer your output, try running python -u in open_port
using term_to_binary/1 and binary_to_term/1 won't work, since they assume that Python is able to encode/decode Erlang External Term Format, which does not seem to be the case. If you want to go this route, check out ErlPort
Does your Param contain the command limiter for Python? (in this case I assume newline, "\n"). Also, list_to_binary/1 and then a term_to_binary/1 feels kinda wrong. term_to_binary/1 directly (including the newline) should be sufficient.