Check Your Services with Ruby
I just got my Pickaxe v2 book in the mail today and have already put it to good use writing a script to check that the services for a host are up and responding. It uses many of the libraries included with Ruby but also another library ‘net-ping’ which you can get with a gem install net-ping. To use it all you have to do is to call the script with one to four parameers:
- First is the host you want to check, i.e. theadmin.org
- Second is the username to login to for FTP, i.e. user-bob (this will default to guest is not defined)
- Third is the password to login to for FTP, i.e. bobpassword (this will default to guest is not defined)
- Fourth is where to place the logfile, i.e. /home/bob/server.log (this will default to /tmp/server_up.log)
Here is a link to the code, and here is it for viewing:
#!/usr/bin/env ruby # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # Program to check that certin services are running on a host # # Copyright (c) 2006 Eric Davis# Released under the MIT License # Details: http://dropbox.theadmin.org/bin/server_up/LICENSE.txt # # Last Revision: [2006/04/27] # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # require 'rubygems' require 'net/ping' require 'net/http' require 'net/smtp' require 'net/ftp' require 'time' def log_error(error) File.open(@log_file, 'a') do |log| log.puts Time.now.rfc2822.to_s + ": " + error end end def check_ping(host) if not Net::PingExternal.new(host).ping log_error("Error: #{host} is not responding to a ping") end end def check_mail(host, port=25, ehlo=host) begin Net::SMTP.start(host, port, ehlo) do |smtp| log_error("Mail Server down") unless smtp.started? end rescue SocketError => socket_error log_error("Error Connecting To SMTP: #{socket_error}") rescue TimeoutError => timeout_error log_error("SMTP connection timed out: #{timeout_error}") end end def check_web(host, file='/') begin Net::HTTP.start(host) do |http| response = http.get(file) if not response.code.match(/200/) log_error("Web Server down or not resonding: #{response.code} #{response.message}") end end rescue SocketError => socket_error log_error("Error Connecting To Web: #{socket_error}") rescue TimeoutError => timeout_error log_error("Web connection timed out: #{timeout_error}") end end def check_ftp(host, login, password) begin Net::FTP.open(host) do |ftp| log_error("FTP Server down or not responding #{ftp.last_response_code}") unless ftp.last_response_code.match(/220/) if password.empty? ftp.login(login) else ftp.login(login, password) end end rescue Net::FTPPermError => login_error log_error("FTP Server not allowing logins for '#{login}' using '#{password}': #{login_error}") rescue SocketError => socket_error log_error("Error Connecting To FTP: #{socket_error}") rescue TimeoutError => timeout_error log_error("FTP connection timed out: #{timeout_error}") end end ftp_user = ARGV[1] || 'guest' ftp_password = ARGV[2] || 'guest' @log_file = ARGV[3] || '/tmp/server_up.log' check_ping(ARGV[0]) check_mail(ARGV[0]) check_web(ARGV[0]) check_ftp(ARGV[0], ftp_user, ftp_password)
Eric Davis
Comments
-
Aieee! It's pretty clear you're just starting Ruby--you've ignored one of its most powerful features (blocks), and duplicated a ton of code in the process. Instead of having a ton of places where you rescue Socket/Timeout errors and present a generic message, do something like this:
def check_service(type) begin log_error("#{type} server down or not responding") unless yield rescue SocketError => socket_error log_error("Error connecting to #{type}: #{socket_error}") rescue TimeoutError => timeout_error log_error("#{type} connection timed out: #{timeout_error}") end end def check_mail(host, port=25, ehlo=host) check_service("SMTP") do Net::SMTP.start(host, port, ehlo) do |smtp| return smtp.started? end end endThis is just a rough idea, but I'm sure you get the picture. -
Seems that my pretty Ruby formatting was trashed :\ Ah well, copy/paste it into a text editor and you should be able to recreate it in its original form. Let me know if you end up implementing my suggestion--it would be interesting to hear about.
-
Yep, Ruby is still new to me (this is one of the larger scripts I have written that is actually useful). That definitely makes cleaner, I will have to try it out. I also planned to add some unit tests to it also. (I also adjusted your formatting so it should come out correct now)
