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.www.freelancingdigest.com/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
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)