RSS
 

Posts Tagged ‘ragios’

Developing Ragios Version 0.5+

13 Apr

I have started testing design ideas for Ragios version 0.5+. Ragios started as a fun way to play with Linux servers and hack the Ruby language. Since then I started using Ragios to monitor web services for my business. Ragios is still very much in alpha stage but its slowly getting somewhere* and I am really enjoying the journey.

Below are some design goals for version 0.5+

Goals

  • Create a plugin architecture, so that all monitors (example HTTP, DNS,process monitors) are added as plugins. This will allow developers to easily write customized plugins. OR easily install plugins written by other developers.
  • Create a simple http server for Ragios that responds to REST requests. This will enable other apps to communicate with Ragios via REST. Example a Rails, Sinatra or javascript app could provide a Web User Interface for Ragios via REST. The datafeed from Ragios could be fed to a webpage, blog, widget or mobile app via REST.
  • Add ability to persist Ragios information and real-time statistics to a database. This will allow service performance monitoring overtime. It will also enable better control of monitors.

 
I have started working on the first goal. In the new design all monitors are plugins. These plugins are simple ruby classes that can monitor URLs, system processes, Mail servers etc.

I hope to keep the same simple syntax for Ragios

    monitoring  =  { :monitor => 'url',
                   :every => '5m',
                   :test => 'video datafeed test',
                   :url => 'http://www.datafeed.com/resources/videos/1',
                   :contact => 'admin@mail.com',
                   :via => 'gmail',
                   :notify_interval => '6h'
 
                  },
                  {:monitor =>'http',
                   :every => '30s',
                   :test => 'Http connection to client A website',
                   :domain => 'www.clientA.com',
                   :contact => 'admin@mysite.com',
                   :via => 'twitter',
                   :notify_interval => '6h'
                  }
 
  Ragios::Monitor.start monitoring

Below is a Gist I created to test design ideas for the new plugin system. I will be updating the Gist as I code in real time. The end result will be the bare bones design for the new system. After I get a workable design I will update the Github Repo here.

 

Moving Ragios To Github

15 Oct

I moved Ragios to github. Its still rough around the edges but i will clean it up soon. I will be pushing updates there and blogging some changes here. Its all just for fun.

Ragios Github Repo: http://github.com/obi-a/Ragios

 
No Comments

Posted in St. Ruby

 

St. Ruby: Adding a Daemon and a Scheduler

09 Oct

Its time to add a real scheduler to the St. Ruby (Ragios) system. We need to be able to set time intervals for each system test performed by Ragios. The system admin sets the time interval for ragios to perform each test.

The Scheduler
We need to add a time_interval attribute to the SystemMonitor Class. Ragios will run the test_command method every time_interval.

#base class that defines the behavior of all system monitors
class SystemMonitor
...
    attr_reader :time_interval
 
   #defines the tests to run on a system
   def test_command
   end
...
end

Time interval could be in seconds, minutes, hours or combined.
Example

@time_interval = '3m'  #means the test will run every 3 minutes
@time_interval = '4h'  #every 4 hours
@time_interval = '30s' #every 30 seconds
@time_interval = '6h30m' #every 6 hours 30minutes

We need a scheduler to execute the tests every Time Interval. We will use the rufus-scheduler rubygem for this.

Installing the gem

sudo gem install rufus-scheduler --source http://gemcutter.org

Sample code using the scheduler

require 'rubygems'
require 'rufus/scheduler'
 
scheduler = Rufus::Scheduler.start_new
 
scheduler.every '40m' do
    puts 'download news feed'
end
 
scheduler.every '3h' do
    puts 'ping remote server'
end

Now lets implement a scheduler for Ragios.

#defines how services will be monitored
class Service < SystemMonitor
    def initialize
     super
    end
end
 
class TestServiceA < Service
   def initialize
      @test_description  = "Test Service A"
      @time_interval = '8h'
      super
   end
 
   def test_command
      #test servcie A
      #return TRUE if test passed; FALSE if failed;
   end
 
  def failed
  end
end #end of TestServiceA
 
class TestServiceB < Service
   def initialize
      @test_description  = "Test Service B"
      @time_interval = '45m'
      super
   end
 
  def test_command
      #test servcie B
      #return TRUE if test passed; FALSE if failed;
   end
 
  def failed
  end
end #end of TestServiceB
 
class TestServiceC < Service
   def initialize
      @test_description  = "Test Service C"
      @time_interval = '20s'
      super
   end
 
  def test_command
      #test servcie C
      #return TRUE if test passed; FALSE if failed;
   end
 
  def failed
  end
end #end of TestServiceC
 
jobs = [ TestServiceA.new, TestServiceB.new, TestServiceC.new]
 
puts "Welcome to Ragios"
puts "Initializing"
 
...
 
#schedule all the jobs to execute test_command() at every time_interval
scheduler = Rufus::Scheduler.start_new
jobs.each do |job|
    scheduler.every job.time_interval do
     begin
       if job.test_command
           puts job.test_description + "   [PASSED]" + " Created on: "+ Time.now.to_s
       else
           puts job.test_description +   "   [FAILED]" + " Created on: "+ Time.now.to_s
           job.failed
       end
       #catch all exceptions
      rescue Exception
          puts "ERROR: " +  $!  + " Created on: "+ Time.now.to_s
          job.error_handler
      end
   end #end of scheduler
end
 
#trap Ctrl-C to exit gracefully
puts "PRESS CTRL-C to QUIT"
  loop do
  trap("INT") { puts "\nExiting"; exit; }
    sleep(3)
  end

In the sample code, we have 3 tests running at different time intervals, we set the Tests to run on the Ragios system here;

jobs = [ TestServiceA.new, TestServiceB.new, TestServiceC.new]

We use the rufus-scheduler to set each test to run it’s test_command at its own specified time interval.
When a test fails it calls the failed method for that test.

scheduler = Rufus::Scheduler.start_new
jobs.each do |job|
    scheduler.every job.time_interval do
     begin
       if job.test_command
           puts job.test_description + "   [PASSED]" + " Created on: "+ Time.now.to_s
       else
           puts job.test_description +   "   [FAILED]" + " Created on: "+ Time.now.to_s
           job.failed
       end
       #catch all exceptions
      rescue Exception
          puts "ERROR: " +  $!  + " Created on: "+ Time.now.to_s
          job.error_handler
      end
   end #end of scheduler
end

We also added an Exception handler, in case the test_command or failed method throws an exception. This is useful because it means there maybe a bug in the ruby code for the test or something wrong with the test. We want to alert the system admin about the Exception. I added a new method called error_handler to the SystemMonitor Class (the superclass of all tests). This will help system admins and developers fix bugs in the test’s ruby code. $! is a ruby global variable that holds the details of the last Exception that occurred in the system.

From the view of a system admin Ragios is running tests but the tests are referred to as jobs in the code. The reason for this is that under the hood, Ragios views the tests as jobs. As far as Ragios is concerned its just running a bunch of jobs at their scheduled time intervals. This is a layer of abstraction. Ragios doesn’t know what a test is. It views them as jobs while a system admin views it as tests. This is why I call it tests in the description while its called jobs in the code. (Eventually we will hide all this stuff inside an object).

Finally, we want Ragios to run until its signaled to quit by a CTRL-C from the computer user. We will trap CTRL-C so that Ragios can exit gracefully.

puts "PRESS CTRL-C to QUIT"
  loop do
  trap("INT") { puts "\nExiting"; exit; }
    sleep(3)
  end

Real World Example
Lets try a real-world test. We will use the TestWebpageForHttp200 that tests a website to check if the home page is loading. It sends a http request to the webpage and returns TRUE (test passed) when it gets a http 200 response. It returns FALSE (test failed) when it gets a different http response code from 200.

class TestWebpageForHttp200 < Service
 
   attr_reader :test_url
 
   def initialize
        @contact = "obi@mail.com"
        @describe_test_result = "HTTP Request to " + @test_url
        super
        @time_interval = '1h'
   end
 
   #returns true when http request to test_url returns a 200 OK Response
   def test_command
     begin
           response = Net::HTTP.get_response(URI.parse(test_url))
           @test_result = response.code
 
          if response.code != "200"
               return FALSE
         else
	          return TRUE
         end
 
     rescue Exception
            @test_result =  $! # $! global variable reference to the Exception object
            return FALSE
     end
 
  end
 
end

This test will also return FALSE ( test failed) when the http request encounters an Exception such as a Timeout::Error or a BAD URL. After each test the response code of the http request will be stored in the @test_result variable. When the http request encounters an Exception, the details of the exception is stored in the @test_result variable.

Now lets write some specific tests that monitors real websites using TestWebpageForHttp200.

class TestMySite < TestWebpageForHttp200
   def initialize
      @test_description  = "My Website Test"
      @test_url = "http://www.whisperservers.com/blog/"
      super
   end
end
 
class TestMyBlog < TestWebpageForHttp200
#tests my blog, to check if the blog is loading
 
   def initialize
      @test_description  = "My Blog Test"
      @test_url = "http://obi-akubue.homeunix.org/"
      super
   end
end
 
class TestFakeSite < TestWebpageForHttp200
#tests a website that doesn't exist this test will always fail
   def initialize
      @test_description  = "Fake website"
      @test_url = "http://wenosee.org/"
      super
   end
end
 
jobs = [ TestMySite.new, TestMyBlog.new, TestFakeSite.new]
 
puts "Welcome to Ragios"
puts "Initializing"
...
#schedule all the jobs to execute test_command() at every time_interval
scheduler = Rufus::Scheduler.start_new
jobs.each do |job|
    scheduler.every job.time_interval do
     begin
       if job.test_command
           puts job.test_description + "   [PASSED]" + " Created on: "+ Time.now.to_s
       else
           puts job.test_description +   "   [FAILED]" + " Created on: "+ Time.now.to_s
           job.failed
       end
       #catch all exceptions
      rescue Exception
          puts "ERROR: " +  $!  + " Created on: "+ Time.now.to_s
          job.error_handler
      end
   end #end of scheduler
end
 
#trap Ctrl-C to exit gracefully
puts "PRESS CTRL-C to QUIT"
  loop do
  trap("INT") { puts "\nExiting"; exit; }
    sleep(3)
  end

The tests in the code above will run every hour because they all extend TestWebpageForHttp200 which has time_interval set to ’1h’. If we want to set any of the tests to a different time interval we simply set the time_interval attribute in its initialize method.

I included a test to a fake website that doesn’t exist, this test will always fail.

class TestFakeSite < TestWebpageForHttp200
#tests a website that doesn't exist this test will always fail
   def initialize
      @test_description  = "Fake website"
      @test_url = "http://wenosee.org/"
      super
   end
end

When this test fails the system admin will receive an alert message like this via email or twitter.

Fake website FAILED!
HTTP Request to http://wenosee.org/ = getaddrinfo: Name or service not known
Created on: Tue Oct 05 17:49:49 -0400 2010

Ragios is able to give the system admin very detailed information on what went wrong when a test fails.

View the complete source code here
ragios.rb: http://gist.github.com/608890
Edit: View the source for the Ragios system here: http://github.com/obi-a/Ragios

The Daemon
Now we need Ragios to run as a Daemon process. Luckily, we have the Daemons ruby gem for this.
To install the gem

sudo gem install daemons

Lets write a script to make ragios.rb run as a daemon.
ragiosd

#!/usr/bin/ruby
 
  require 'rubygems'
  require 'daemons'
 
  options = {
  :app_name   => "ragios",
  :log_output => true,
  :monitor    => true
}
Daemons.run('ragios.rb', options)

This script should be in the same folder with ragios.rb.
To start Ragios as a daemon, we simply run the script.

Start the daemon

ruby ragiosd start

Stop the daemon

ruby ragiosd stop

Restart the daemon

ruby ragiosd restart

Check Status of the daemon

ruby ragiosd status

Test the daemon

ruby ragiosd run

In the ragiosd script, we have set the daemon to log its output and monitor the process.

 options = {
  :app_name   => "ragios",
  :log_output => true,
  :monitor    => true
}

When we start the daemon it will log its output in a file called ragios.output in the same folder with ragiosd. It will also log its actions in a log file called ragios.log

View the source for ragiosd here:
http://github.com/obi-a/Ragios

 

Sending Tweet Alerts with St. Ruby

22 Sep

As a modern system we need St. Ruby (Ragios) to be able to tweet alerts to system admins and web masters when a test fails.

To do this, first we need to create and register an App on Twitter. This is the App that Ragios will use to tweet the alerts. So we create and register a twitter app from here: http://twitter.com/apps/new. After we register the App, Twitter will give us a consumer_key and a consumer_secret. We will need this later.

Next we need to create a new twitter account for the Ragios system. This is the Twitter account that will tweet the alerts. To receive the tweets the system admin should follow this account. Of course this account should be set to private on twitter.

After we create the account, we need to grant our twitter app access to it. Lets write a script to do that.

We need the oauth ruby gem.

sudo gem install oauth

This ruby script will do the trick;
twitter_auth.rb

#!/usr/bin/ruby
require 'rubygems'
require 'oauth'
 
consumer = OAuth::Consumer.new(
  'consumer key',
  'consumer secret',
  {:site => 'http://twitter.com'}
)
 
request_token = consumer.get_request_token
 
puts "Twitter App Authorize URL \n" + request_token.authorize_url
puts "Enter PIN:"
pin = STDIN.readline.chomp
 
access_token = request_token.get_access_token(:oauth_verifier => pin)
 
puts "access token: " + access_token.token
puts "access secret: " + access_token.secret

We use the ‘consumer_key’ and ‘consumer secret’ Twitter generated for our app. We need this to create a request_token which gives us an authorization URL. This is the URL which we use to ALLOW or DENY, the Twitter App access to the twitter account that will tweet the alerts.

The script will display the authorization URL for our App. Open this URL on a browser and click ALLOW to grant access. Twitter will give you a PIN number. Enter that PIN number on the prompt. This PIN number is our oauth_verifier which is used to generate the access_token.

The access_token and access_secret is all we need to gain read and write access to the twitter account. So we don’t need a twitter username and password to access the account. Thats the fun in using oauth. We need to save the access_token and access_secret somewhere to use later for tweeting.
This script from BeefyApps Blog, Simple Ruby OAuth with Twitter and this great post OAuth Explained and What It Is Good For, saved me a lot of trouble.

Now lets write a simple ruby script that tweets.

We need the twitter ruby gem;

sudo gem install twitter

Sample script 1:
For twitter gem v1.0 and above
tweet.rb

#!/usr/bin/ruby
require 'rubygems'
require 'twitter'
 
Twitter.configure do |config|
config.consumer_key = 'Consumer Key'
config.consumer_secret = 'Consumer secret'
config.oauth_token = 'access token'
config.oauth_token_secret = 'access secret'
end
 
Twitter.update("first tweet, this is a test")

We use the same ‘Consumer Key’ and ‘Consumer secret’ that Twitter generated for our App. We also use the ‘access token’ and ‘access secret’ we generated in the twitter_auth.rb script. The last line of the tweet.rb script will tweet the test message.

Sample script 2;
For twitter gem pre v1.0
[Edit March 13,2011] The code below only works with twitter gem below version 1.0. It doesn’t work with twitter gem version 1.0+ Thanks to @pablochacin for pointing this out in the comments. Note: Ragios uses twitter gem v0.9.12.

tweet1.rb

#!/usr/bin/ruby
require 'rubygems'
require 'twitter'
 
oauth = Twitter::OAuth.new('Consumer Key', 'Consumer secret')
oauth.authorize_from_access('access token', 'access secret')
 
client = Twitter::Base.new(oauth)
client.update('first tweet, this is a test')

Now lets add Tweet Alerts to our Ragios System
First, we need to create a new Class that knows how to tweet. This class will hide the dirty details of tweeting from the rest of the system.

#this class hides the messy details of tweeting from rest of the system
class Tweet
 
  def initialize
       oauth = Twitter::OAuth.new('Consumer Key', 'Consumer secret')
       oauth.authorize_from_access('access token', 'access secret')
 
       @client = Twitter::Base.new(oauth)
  end
 
 def tweet message
      @client.update(message)
 end
 
end

Note: I have changed the Naming convention for Ragios to use CamelCase for Class names and more_like_this for method names. Thanks to great tips here “Little Known Ways to Ruby Mastery by Jamie van Dyke”

Next we need to add a tweet_alert method to the SystemMonitor Class.

The tweet_alert method

def tweet_alert
 
     Tweet.new.tweet @test_description + " FAILED!  " + @describe_test_result + " = " + @test_result + " Created on:  " + Time.now.to_s
 end

The tweet_alert method is invoked by the failed method. The system admin can choose to use tweet alerts or email alerts by editing the failed method.

 #defines the action to take when a test fails
   #- May send email, SMS or tweet to the system admin
   #- May also take action to fix the issue like restart a process/service
   def failed
       tweet_alert
       #email_alert
   end

In the above sample, the System will send out a tweet when a test fails.

New SystemMonitor Class with the tweet_alert method

#base class that defines the behavior of all system monitors
class SystemMonitor
 
    # a short description of the test performed by this system monitor
   attr_reader :test_description
 
   #hostname of the system being monitored
   attr_reader :hostname
 
   #ip address of the system being monitored
   attr_reader :address
 
   #email address of admin to contact when a test fails
   attr_reader :contact
 
   #results of a test
   attr_reader :test_result
 
    #describes the test result, this gives technical details on the test_result
    #This gives the sysadmin info on the technical details of the test results
    attr_reader :describe_test_result
 
   def initialize
 
   end
 
   #defines the tests to run on a system
   def test_command
   end
 
   #defines the action to take when a test fails
   #- May send email, SMS or tweet to the system admin
   #- May also take action to fix the issue like restart a process/service
   def failed
       tweet_alert
       #email_alert
   end
 
  def tweet_alert
 
     Tweet.new.tweet @test_description + " FAILED!  " + @describe_test_result + " = " + @test_result + " Created on: "+ Time.now.to_s
 end
 
 
   def email_alert
       puts 'sending mail alert...'
       Pony.mail  :to => @contact,
                  :from => 'Ragios',
                  :subject => @test_description + " FAILED",
              :body => @test_description + " FAILED \n\n" + @describe_test_result + " = " + @test_result +  "\n\n Created on: " + Time.now.to_s
   end
end

Now lets test the system with a sample test, that monitors my website and alerts me (by posting a tweet) when the site is down.
This is the sample test. (The code is explained in more detail here)

#defines how services will be monitored
class Service < SystemMonitor
    def initialize
     super
    end
end
 
#monitors a webpage to check if the site is loading
#PASSED if it gets a HTTP 200 Response status code from the website
class TestWebpageForHttp200 < Service
 
   attr_reader :test_url
 
   def initialize
        @contact = "obi@mail.com"
        @describe_test_result = "HTTP Request to " + @test_url
        super
   end
 
   #returns true when http request to test_url returns a 200 OK Response
   def test_command
       response = Net::HTTP.get_response(URI.parse(test_url))
        @test_result = response.code
       if response.code != "200"
            return FALSE
       else
	    return TRUE
       end
   end
 
end
 
class TestMySite < TestWebpageForHttp200
   def initialize
      @test_description  = "My Website Test"
      @test_url = "http://www.whisperservers.com/blog/"
      super
   end
end

When this test fails the system will tweet a message like this;

My Website Test FAILED! HTTP Request to http://www.whisperservers.com/blog/ = 500
Created on: Wed Sep 22 13:55:21 -0400 2010

So we are now all set with Tweet Alerts for St. Ruby.

Source for Ragios:http://github.com/obi-a/Ragios.

 

Adding Email Alert to Ragios (St. Ruby)

19 Sep

In the last blog post, I started working on St. Ruby, an Object Oriented Ruby Based Network and System Monitoring System. Its just for fun and mostly an excuse to play with ruby and Linux servers.

I have added Email alert to Ragios. Anytime a test fails Ragios fires up an email to the system admin.

We are using the Pony ruby gem to send the email alerts.

To install the Pony gem;

sudo gem install pony

We are using sendmail for mail transport; Installing sendmail on Ubuntu;

sudo apt-get install sendmail

Testing sendmail to verify it works

echo "Subject: test" | /usr/lib/sendmail -v me@domain.com

(courtesy of cool commands)

Sample code to send email with Pony via sendmail;

#!/usr/bin/ruby
require 'rubygems'
require 'pony'
puts 'sending mail...'
Pony.mail :to => 'test@example.com',
          :from => 'obi',
          :subject => 'here we get near yeah yeah!',
          :body => 'wsup!'

Ragios Email Alert
To add the email alert to Ragios we just needed to add a new method called email_alert to the System Monitor Class. This method is invoked by the failed method. Ragios runs the failed method anytime a test fails in the system.

The email_alert method

 def email_alert
       puts 'sending mail alert...'
       Pony.mail  :to => @contact,
                  :from => 'Ragios',
                  :subject => @test_description + " FAILED",
              :body => @test_description + " FAILED \n\n" + @describe_test_result + " = " + @test_result
   end

We also added a new attribute @decribe_test_result, this describes the meaning of @test_result, this is very useful in reporting to the system admin what exactly what went wrong. More on this later.

The new System monitor class

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
#base class that defines the behavior of all system monitors
class System_monitor
 
    # a short description of the test performed by this system monitor
   attr_reader :test_description
 
   #hostname of the system being monitored
   attr_reader :hostname
 
   #ip address of the system being monitored
   attr_reader :address
 
   #email address of admin to contact when a test fails
   attr_reader :contact
 
   #results of a test
   attr_reader :test_result
 
    #describes the test result, this gives technical details on the test_result
    #This gives the sysadmin info on the technical details of the test results
    attr_reader :describe_test_result
 
   def initialize
 
   end
 
   #defines the tests to run on a system
   def test_command
   end
 
   #defines the action to take when a test fails
   #- May send email or SMS to the admin under contact
   #- May also take action to fix the issue like restart a process/service
   def failed
       email_alert
   end
 
   def email_alert
       puts 'sending mail alert...'
       Pony.mail  :to => @contact,
                  :from => 'Ragios',
                  :subject => @test_description + " FAILED",
              :body => @test_description + " FAILED \n\n" + @describe_test_result + " = " + @test_result
   end
end

On the last post we had a sample test class Test_webpage_for_http_200 , that tests a website to see if the home page is loading, it returns PASSED when the home page loads and FAILED when the site is down. Now that we have an email alert, we just need to add a contact email address to be alerted when the test fails.

New Test_webpage_for_http_200 class

#monitors a webpage to check if the site is loading
#PASSED if it gets a HTTP 200 Response status code from the website
class Test_webpage_for_http_200 < Service
 
   attr_reader :test_url
 
   def initialize
        @contact = "obi@mail.com"
        @describe_test_result = "HTTP Request to " + @test_url
        super
   end
 
   #returns true when http request to test_url returns a 200 OK Response
   def test_command
       response = Net::HTTP.get_response(URI.parse(test_url))
        @test_result = response.code
       if response.code != "200"
            return FALSE
       else
	    return TRUE
       end
   end
 
end

If we wanted to use the same contact email for all service tests, we simply assign the email address to @contact on the Service class. If we wanted a system wide contact email we just initialize @contact on the System_monitor class which is the base class of the system.

A specific test on my website looks like this;

class Test_my_site < Test_webpage_for_http_200
   def initialize
      @test_description  = "My Website Test"
      @test_url = "http://www.whisperservers.com/blog/"
      super
   end
end

An Email Alert from Ragios when this test fails will looks like this;

    From: Ragios@domain.com
        To: obi@mail.com
 
My Website Test FAILED
 
HTTP Request to http://www.whisperservers.com/blog/ = 500

This tells the site admin exactly what is going on.

Edit: View the most recent source code here: http://github.com/obi-a/Ragios

New Ragios complete Source code with Email Alert;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
#!/usr/bin/ruby
#:Title   :Ragios (aka St. Ruby)
#:Date    :9/16/2010
#:Author  :Obi Akubue
#:Version :0.2
#description: This is the framework for a Ruby Based System and Network Monitoring Tool
 
 
require 'net/http'
require 'rubygems'
require 'pony'
 
#base class that defines the behavior of all system monitors
class System_monitor
 
    # a short description of the test performed by this system monitor
   attr_reader :test_description
 
   #hostname of the system being monitored
   attr_reader :hostname
 
   #ip address of the system being monitored
   attr_reader :address
 
   #email address of admin to contact when a test fails
   attr_reader :contact
 
   #results of a test
   attr_reader :test_result
 
    #describes the test result, this gives technical details on the test_result
    #This gives the sysadmin info on the technical details of the test results
    attr_reader :describe_test_result
 
   def initialize
 
   end
 
   #defines the tests to run on a system
   def test_command
   end
 
   #defines the action to take when a test fails
   #- May send email or SMS to the admin under contact
   #- May also take action to fix the issue like restart a process/service
   def failed
       email_alert
   end
 
   def email_alert
       puts 'sending mail alert...'
       Pony.mail  :to => @contact,
                  :from => 'Ragios',
                  :subject => @test_description + " FAILED",
              :body => @test_description + " FAILED \n\n" + @describe_test_result + " = " + @test_result
   end
end
 
#defines how computers,servers,network devices will be monitored
class Host < System_monitor
    def initialize
     super
    end
 
end
 
#defines how services will be monitored
class Service < System_monitor
    def initialize
     super
    end
end
 
 
#monitors a webpage to check if the site is loading
#PASSED if it gets a HTTP 200 Response status code from the website
class Test_webpage_for_http_200 < Service
 
   attr_reader :test_url
 
   def initialize
        @contact = "obi@mail.com"
        @describe_test_result = "HTTP Request to " + @test_url
        super
   end
 
   #returns true when http request to test_url returns a 200 OK Response
   def test_command
       response = Net::HTTP.get_response(URI.parse(test_url))
        @test_result = response.code
       if response.code != "200"
            return FALSE
       else
	    return TRUE
       end
   end
 
end
 
class Test_my_site < Test_webpage_for_http_200
   def initialize
      @test_description  = "My Website Test"
      @test_url = "http://www.whisperservers.com/blog/"
      super
   end
end
 
class Test_my_blog < Test_webpage_for_http_200
#tests my blog, to check if the blog is loading
 
   def initialize
      @test_description  = "My Blog Test"
      @test_url = "http://obi-akubue.homeunix.org/"
      super
   end
end
 
 
jobs = [ Test_my_site.new, Test_my_blog.new]
 
jobs.each do |job|
 puts job.test_description
 if job.test_command
        puts "   [PASSED]"
     else
        puts "   [FAILED]"
        job.failed
     end
end

[UPDATE 10-1-2010] View the complete Ragios source with latest revisions
http://github.com/obi-a/Ragios.

 
 

[DEPRECATED]Ragios: Ruby based System and Network Monitoring Tool

31 Aug

This post has been deprecated. See the new version of Ragios here: http://github.com/obi-a/Ragios

While reading the book “Nagios: system and Network Monitoring” by Wolfgang Barth, I thought it will be a good idea to write a Ruby based Object Oriented System and Network Monitoring tool similar to Nagios.

So I started writing such a tool. Since it was inspired by Nagios, I will call it Ragios (Ruby Agios) aka Saint Ruby (St. Ruby) since Agios is Saint in Greek.

This is all just for fun and educational purposes.

Ragios could be used to monitor any type of system including servers, workstations, switches, routers, system services and applications, locally or over a network. The system admin can define the tests he wants to run on the system or re-use tests written by other developers. The tests run periodically on the system. When a test fails the admin receives an email or SMS alert from Ragios. Everything is written in ruby, the configuration settings are all in ruby syntax and Ragios itself is a ruby script.

Ragios is Object Oriented so everything is an object. The Base object is the System_monitor defined by the System_monitor class. This class defines the behavior of all system monitors.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class System_monitor
#base class that defines the behavior of all system monitors
 
   attr_reader :test_description   # a short description of the test performed by this system monitor
   attr_reader :hostname #hostname of the system being monitored
   attr_reader :address   #ip address of the system being monitored
   attr_reader :contact    #email address of admin to contact when a test fails
   attr_reader :test_result #results of a test
 
   def initialize
   end
 
   def test_command
   #defines the tests to run on a system
   end
 
   def failed
   #defines the action to take when a test fails
   #- May send email or SMS to the admin under contact
   #- May also take action to fix the issue like restart a process/service
   end
end

The method test_command defines the test that will be performed on the system periodically by the system monitor. If the test is successful test_command will return TRUE, if it fails the method will return FALSE. The test_command method can run any type of test, it just needs to return values TRUE for a PASSED test and FALSE for a FAILED test.

The failed method defines the actions to be performed when a test fails. These actions may include sending email or SMS to alert the system admin about a problem. It may also include actions to fix the problem.

After every test any results from the test like an error message for a failed test is saved in the test_result variable. This should be implemented in the test_command method.

Ragios monitors 2 types of systems, Hosts and Services. Hosts are devices that run on a network like computers, routers, switches and servers. Services are applications and processes like a web server, database, web apps, and system processes.

Hosts and Services both extend the System_monitor class. They both inherit all the characteristics of a System_monitor.

The Host class

1
2
3
4
5
6
7
class Host < System_monitor
#defines how computers,servers,network devices will be monitored
 
    def initialize
     super
    end
end

The Service class

1
2
3
4
5
6
class Service < System_monitor
#defines how services, processes and applications will be monitored
    def initialize
     super
    end
end

Now we have the basic framework in place. With Ragios the system admin implements his own system monitors or reuses system monitors already implemented by other developers.

Lets implement a simple system monitor that monitors a webpage and alerts the owner when the site is down. This is simply done by sending http requests to the site’s home page and alerting the site owner if it fails to get a HTTP 200 OK status response from the server.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
class Test_webpage_for_http_200 < Service
#monitors a webpage to check if the site is loading
#PASSED if it gets a HTTP 200 Response status code from the website
 
   attr_reader :test_url
 
   def initialize
        super
   end
 
   def test_command
     #returns true when http request to test_url returns a 200 OK Response
       response = Net::HTTP.get_response(URI.parse(test_url))
        @test_result = response.code
       if response.code != "200"
            return FALSE
       else
	    return TRUE
       end
   end
 
   def failed
         #send email notification to site owner
         #not yet implemented
   end
end

Test_webpage_for_http_200 extends the Service class because it is testing http which is a service. it also has all the characteristics of the base class System_monitor. We just needed to override the test_command method to implement our specific test.

def test_command
     #returns true when http request to test_url returns a 200 OK Response
       response = Net::HTTP.get_response(URI.parse(test_url))
        @test_result = response.code
       if response.code != "200"
            return FALSE
       else
	    return TRUE
       end
   end

test_command sends http requests to the test_url and returns TRUE when it gets a 200 OK Response, returns FALSE when it gets a different response code. The response code is saved in @test_result as the result of this test. This value gives a system admin insight on what has gone wrong.

The failed method should define the actions to take when a test fails. In this case it sends an email to notify the site owner. The email feature is not yet implemented.

Test_webpage_for_http_200 is a generic system monitor, it doesn’t test any particular site, we still need to write system monitors that test specific sites for us. These monitors will be subclasses of Test_webpage_for_http_200. Lets write some now

1
2
3
4
5
6
7
8
class Test_my_blog < Test_webpage_for_http_200
#monitors my blog, to check if the blog's home page is loading
   def initialize
      @test_description  = "Testing My Blog"
      @test_url = "http://obi-akubue.homeunix.org/"
      super
   end
end

Running

Test_my_blog.new.test_command

will send a http request to my blog’s home page http://obi-akubue.homeunix.org/ and return TRUE if it gets a 200 Ok Response and FALSE if it gets anything else.

Lets write another test, this one monitors my website http://whisperservers.com/blog.

1
2
3
4
5
6
7
class Test_my_site < Test_webpage_for_http_200
   def initialize
      @test_description  = "Testing my website site"
      @test_url = "http://www.whisperservers.com/blog/"
      super
   end
end

Running

Test_my_site.new.test_command

will send a http request to my site’s home page http://www.whisperservers.com/blog/ and return TRUE if it gets a 200 Ok Response and FALSE if it gets anything else.

Ragios will run all our tests and alert us when a test fails.

1
2
3
4
5
6
7
8
9
10
11
jobs = [Test_my_blog.new, Test_my_site.new]
 
jobs.each do |job|
 puts job.test_description
 if job.test_command
        puts "   [PASSED]"
     else
         puts "   [FAILED]"
         job.failed
     end
end

We just need to add our tests to the jobs Array.

jobs = [Test_my_blog.new, Test_my_site.new]

Ragios will alert us when a test fails by calling the failed method.

Complete source code for Ragios

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
#!/usr/bin/ruby
#:Title   :Ragios (aka St. Ruby)
#:Date    :8/26/2010
#:Author  :Obi Akubue
#:Version :0.1
#description: This is the framework for a Ruby Based System and Network Monitoring Tool
 
 
require 'net/http'
 
class System_monitor
#base class that defines the behavior of all system monitors
 
   attr_reader :test_description   # a short description of the test performed by this system monitor
   attr_reader :hostname #hostname of the system being monitored
   attr_reader :address   #ip address of the system being monitored
   attr_reader :contact    #email address of admin to contact when a test fails
   attr_reader :test_result #results of a test
 
   def initialize
   end
 
   def test_command
   #defines the tests to run on a system
   end
 
   def failed
   #defines the action to take when a test fails
   #- May send email or SMS to the admin under contact
   #- May also take action to fix the issue like restart a process/service
   end
end
 
 
class Host < System_monitor
#defines how computers,servers,network devices will be monitored
 
    def initialize
     super
    end
 
end
 
class Service < System_monitor
#defines how services will be monitored
 
    def initialize
     super
    end
end
 
class Test_webpage_for_http_200 < Service
#monitors a webpage to check if the site is loading
#PASSED if it gets a HTTP 200 Response status code from the website
 
   attr_reader :test_url
 
   def initialize
        @contact = "Obi@whisperservers.com"
        super
   end
 
   def test_command
     #returns true when http request to test_url returns a 200 OK Response
       response = Net::HTTP.get_response(URI.parse(test_url))
        @test_result = response.code
       if response.code != "200"
            return FALSE
       else
	    return TRUE
       end
   end
 
   def failed
         #send email notification to site owner @contact
         #not yet implemented
   end
end
 
class Test_my_site < Test_webpage_for_http_200
   def initialize
      @test_description  = "Testing my website site"
      @test_url = "http://www.whisperservers.com/blog/"
      super
   end
end
 
class Test_my_blog < Test_webpage_for_http_200
#tests my blog, to check if the blog is loading
 
   def initialize
      @test_description  = "Testing My Blog"
      @test_url = "http://obi-akubue.homeunix.org/"
      super
   end
end
 
 
jobs = [ Test_my_site.new, Test_my_blog.new]
 
jobs.each do |job|
 puts job.test_description
 if job.test_command
        puts "   [PASSED]"
     else
        puts "   [FAILED]"
        job.failed
     end
end

In its current form Ragios is just a simple ruby script, the system admin has to edit this script to add tests and configuration settings, or reuse tests already available.

Any setting that applies to more than one test should be added to the initialize method of the super class of those tests. In the example above we added

@contact = "Obi@whisperservers.com"

to the initialize method of Test_webpage_for_http_200. This allows our tests (Test_my_blog and Test_my_site) to use the same contact = "obi@whisperservers.com" by simply calling the super method in their constructor.

Ragios is still incomplete, for now we may set it to run hourly as a cron job or in the future we may make it into a daemon. This is just the basic framework to extend and play with.

[UPDATE 10-1-2010] View the complete Ragios source with latest revisions
http://github.com/obi-a/Ragios.

 
 
Premium Wordpress Plugin