#!/usr/bin/env ruby require "net/http" require "net/ping" require "socket" class Host def initialize s parts = s.split @hostname = parts.first @services_and_ports = {} @sites = [] parts.slice(1, parts.size).each { |part| if part[0] == "@" url = part.slice 1, part.size @sites << url else service, port_and_protocol = part.split ":" port, protocol = port_and_protocol.split "/" @services_and_ports["#{service}/#{protocol}"] = [port.to_i, protocol] end } end def hostname return @hostname end def up? hostname ping = Net::Ping::External.new @hostname ping.ping? end def service_up? service, port, protocol if protocol == "tcp" begin sock = TCPSocket.new @hostname, port sock.close return true rescue return false end elsif protocol == "udp" system "nc -u -z -w 1 #{@hostname} #{port+1} &>/dev/null" return $?.success? else STDERR.write "unknown protocol '#{protocol}'\n" end return false end def site_up? site begin url = URI site response = Net::HTTP.get_response url return response.kind_of? Net::HTTPSuccess rescue return false end end def check ret = {} ret["up"] = up? @hostname return ret if not ret["up"] @services_and_ports.each_key { |k| ret[k] = service_up? k, @services_and_ports[k][0], @services_and_ports[k][1] } @sites.each { |url| ret[url] = site_up? url } return ret end end def main while line = STDIN.gets h = Host.new line puts h.check.to_s end end if __FILE__ == $0 main end