Script to ping computer

Hi everyone!

I’d like to do a page that will show the health of our main system. I need to ping some devices and show the response time.

Is it possible to do this using in a script?

Thanks.

There is a 3rd party ping module that has been created.
http://forum.inductiveautomation.com/t/byes-apps-driver-ping-module-ignition-7-8/7998

Yes I found it but the link is not working…

You can do this natively in python

import os
online = os.system("ping 8.8.8.8") == 0

This os.system("ping ") will return 0 if successful. So comparing it to 0 will get you a boolean value of if the device can be pinged or not.

Edit: I might add there are some nuances to this depending on OS the script is running on, but in general it should work.

I just tested this on Windows, and it returns a 0 when the ping passes or fails.

Kymera has a ping driver that might suit your needs, take a look
http://kymerasystems.com/kymera-pinger-driver/

This is the script you are looking for:

def ping(address):
	import subprocess
	command = 'ping', '%s' % address
	# shell=True hides the shell window, stdout to PIPE enables communicate() to get the ping command result
	process = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE)
	# trimming it to the actual lines with information
	process_out = process.communicate()[0].strip().split('\r\n')
	# print out the return of the ping
	print process_out[1:5]

now just call it inside your script ping('192.168.1.1') and it will ping the address and print out the output

5 Likes

This is working for me in windows. Although I just realized the OP asked for response time too. @c.bertulli looks like he has the best answer.

import os

def ping(ip):
     return os.system("ping " + ip) == 0

print ping("8.8.8.8")
print ping("1.2.3.4")
print ping("4.4.4.4")

If you are running in Unix you’ll need to change the first part of the os.system call to ping -c 5 to limit the number of ping attempts.

This should print out the results of the command and also return a boolean value for each function call. Results should be True, False, False

3 Likes

Working good!

Thanks everone!

1 Like

Well that is weird, I tested your code last night, and it didn't work, and today it does. I stand corrected.

1 Like

Shelling out for this makes me feel very icky, especially when Java already has the native ability to do this and that’s an invitation to accidentally send horrible things to the command line. Why not just:

def ping(address,timeout=2000):
	from java.net import InetAddress
	ip = InetAddress.getByName(address)
	return ip.isReachable(timeout)

This will throw UnknownHostException if the host can’t be looked up, or IOException if the network is broken, so you can handle that case as well, instead of not even knowing it happened unless you parse unexpected command-line output. Or just swallow exceptions, of course.

java.net.* can do all the fun things you thought you needed command-line tools for, and more.

22 Likes

Nice! I like this a lot more.

Another downside to using os.system for ping in Windows is that it writes the ping results to the wrapper.log file. I'm pinging 100 devices every few minutes and this clogs up the log files like so:

Blockquote
INFO | jvm 1 | 2020/10/09 17:45:00 | Pinging 9.9.9.9 with 32 bytes of data:
INFO | jvm 1 | 2020/10/09 17:45:00 | Reply from 9.9.9.9: bytes=32 time<56ms TTL=64
INFO | jvm 1 | 2020/10/09 17:45:00 |
INFO | jvm 1 | 2020/10/09 17:45:00 | Ping statistics for 9.9.9.9:
INFO | jvm 1 | 2020/10/09 17:45:00 | Packets: Sent = 1, Received = 1, Lost = 0 (0% loss),
INFO | jvm 1 | 2020/10/09 17:45:00 | Approximate round trip times in milli-seconds:
INFO | jvm 1 | 2020/10/09 17:45:00 | Minimum = 0ms, Maximum = 0ms, Average = 0ms

1 Like

Hi @silverbacknet,

I am trying this in the Ignition script console but having issue getting it to work. (I am just trying to ping 8.8.8.8) It seems like Java always tries to use TCP Port 7 instead of ICMP. I’ve tried setting the Java Network setting to Direct Connection as the InetAddress documentation suggests that Java will only use ICMP if the privilege can be obtained, but no success.

If you have any suggestions that will be much appreciated.

Thanks!

That’s a toughy. It always tries ICMP first, so I assume that’s blocked on the host, or perhaps just on the Java process. If it works via shelling out, you might be forced to use that.

That’s the only ICMP base Java gives you, raw sockets aren’t available (and generally locked to root/Administrator anyway). If you want to try one that never falls back, you could install icmp4j, which is a lot more flexible for pings/traceroutes and the like, but I’m not sure it’d help too much in this case.

Hm, it’s always possible it’s defaulting to the wrong interface, if there’s an overlap somehow, but that seems very unlikely.

1 Like

Hi @silverbacknet,

Thanks a lot for your reply. Yeah, the shelling out method is working quite well, so will probably stick to it for now. Will have to look into this a bit more when I get a chance.

I attempted to convert and use the java.net implementation with inetAddress and isReachable(). However it seems this method does not work as expected when running ignition as non-root user under Linux. I suppose I could run Ignition as root, or assign root privilege to my 'ignition' system account that I am using to run Ignition but those both seem like worse options than just "shelling out" to run a ping command.
Has anyone identified an easy way to get the java.net method to work with a non-root system user account under Ubuntu?

Add CAP_NET_RAW to your SystemD service's AmbientCapabilities. That will allow .isReachable() to work in a non-root environment. (I recommend also using CAP_NET_BIND_SERVICE so you can use the standard http and https ports with a non-root service.)

2 Likes

Here is a lengthy recap of the steps that lead to success in using java.net (InetAddress, isReachable) on a Linux server (Ubuntu 20.04.5 LTS) with Ignition running as a non-root system user account.

  1. Ran this command...
sudo systemctl edit Ignition-Gateway.service
  1. Added this text... then saved changes.
[Service]
AmbientCapabilities=CAP_NET_RAW CAP_NET_BIND_SERVICE
  1. Restarted the Ignition gateway...
sudo /usr/local/bin/ignition/gwcmd.sh -r
  1. Confirmed the service was running without error
sudo systemctl status Ignition-Gateway.service
  1. Confirmed the new settings appeared in the service configuration
sudo systemctl show Ignition-Gateway.service | grep AmbientCapabilities

At this point the InetAddress isreachable function was still not returning any positive results (all fails).
I noticed that the results of the systemctl status Ignition-Gateway.service command was not showing a recent start date so the `gwcmd.sh -r' command must not have operated at the systemd service level...

  1. Restarted the Ignition Gateway service using systemctl
sudo systemctl restart Ignition-Gateway.service

Then the isReachable function finally started returning positive results (successful pings).

For completeness here is my version of the ping function:

	def ping(host, timeout=2000):
		from java.net import InetAddress 
		# (https://docs.oracle.com/javase/8/docs/api/java/net/InetAddress.html) 	
		ip = InetAddress.getByName(host)
		data = { 
			'isReachable':ip.isReachable(timeout)
			,'hostAddress':ip.getHostAddress()
			,'hostName':ip.getHostName()
		}
		return data
	result = ping('8.8.8.8')

Thanks to @silverbacknet , @pturmel and @kcollins1 for your forum posts that helped me sort this out.
Now to see if I can do similar in a docker container.

3 Likes

Should be able to achieve a similar effect through cap_add (link is for the Compose service configuration, it looks like --cap-add is what you'd use for docker run).

So I followed all of these steps in order to try and get the Java.net ping working from my edge server, but I still am getting nothing but failed pings here. CAP_NET_RAW is in fact set as an AmbientCapability for my Ignition Gateway service and I have reloaded the daemon and restarted the service. Still, nothing works. Is there any other solution to this issue that I am missing?

Should I just resort to running the Ignition service as root?