RSS
 

Archive for the ‘Programming’ Category

Hey programmer, what is it that you do?

01 Dec

Sometimes, I simply can’t put a price on what I do.

Two years ago, I was kidnapped by monkeys, who appeared to be in a trance. They took me to the top of the Swayambhunath Buddhist complex, in Kathmandu. I was told that this was the Monkey Temple. As a monk translated the wishes of the holy monkeys, I discovered that I was required to rewrite the OS of their ancient computer, which had failed to reboot, back in 1839. Since then, they had searched the world for a programmer competent to handle the situation. They were about to give up, as they stumbled onto me, and realized that I was the reincarnation of ChiChu Gomptar, the lead programmer for the CS monkey gang, which had served their monkey king, the creator of this computer. I was flummoxed by its design, as it was made of smooth stones, uniform beads, colored sand, and wooden levers inlaid with gold. I told them that I couldn’t remember anything from my past life. They gave me something to smoke, saying that it would connect me, through the eternal ether, to my previous memories.

It did, and after 25 days of extreme programming, of which I recall no details, I had completed the monumental task. I stood up, and ceremoniously dropped the special IPL bead onto the machine, which then awoke from its 170-year slumber with a mighty roar. The holy monkeys were pleased. They handed over a small golden box, with mysterious carvings. It seemed empty, and I was told not to open it unless my circumstances had become truly dire. I thanked them, both for the box, and for the tremendous experience. Unfortunately, I was not able to sell them continued maintenance for their new OS, but that was mostly due to their language not having the word “maintenance”. Anyway, I have those memories, and this box to use when things go really bad, plus the always-present hope of future adventure.

This was a comment on hacker news. Original source: http://news.ycombinator.com/item?id=3146786

 

How to do a barrell roll

06 Nov

We have all seen Google’s barrel roll trick. The coolest thing about it is that, its done with simple CSS. To see the same effect, place your mouse over this blog post.

Source code for the Barrel roll:

.barrel_roll {
-moz-animation-name: roll; 
	-moz-animation-duration: 4s; 
	-moz-animation-iteration-count: 1; 
	-o-animation-name: roll; 
	-o-animation-duration: 4s; 
	-o-animation-iteration-count: 1; 
	-webkit-animation-name: roll; 
	-webkit-animation-duration: 4s; 
	-webkit-animation-iteration-count: 1; 
}
 
@-moz-keyframes roll { 
	100% { 
		-moz-transform: rotate(360deg);
	}
} 
@-o-keyframes roll { 
	100% { 
		-o-transform: rotate(360deg); 
	} 
} 
@-webkit-keyframes roll {
	100% { 
		-webkit-transform: rotate(360deg); 
	} 
}

Only works in modern browsers like Chrome, Firefox, Opera and Safari. I hope IE will catch up.
Source: http://www.metaltoad.com/blog/how-does-google-do-barrel-roll

 
 

CouchDB Security in Ruby

30 Oct

To get some background on couchDB security read here.

All the code samples below, require the Restclient rubygem. You can install it with the command:

gem install rest-client

And Require it in your code with:

require 'rest_client'

Let’s say your couchDB is in Admin Party mode. To end the admin party and add an admin user:

RestClient.put 'http://127.0.0.1:5984/_config/admins/james', '"ssstepin"',{:content_type => :json}

james is the name of the new admin, and his password is ssstepin. The password needs to be enclosed in double quote,to denote a string in the couchDB configuration.

To authenticate the admin user:

response = RestClient.post 'http://127.0.0.1:5984/_session', 'name=james&password=ssstepin',{:content_type => 'application/x-www-form-urlencoded'}
puts response.cookies
# => {"AuthSession"=>"b2tlOjRFQUJCNzE0OkXtpl9cxR_zbIxvlvW2J60txIwT", "Version"=>"1", "Path"=>"%2F"}

This returns the authentication token for making future requests, on behalf of the authenticated user.

To add a new admin user:

RestClient.put 'http://127.0.0.1:5984/_config/admins/david', '"wuzz234"',{:cookies => {"AuthSession" => "b2tlOjRFQUJCNzE0OkXtpl9cxR_zbIxvlvW2J60txIwT"}}

We added a new admin david with password wuzz234, we made the request on behalf of james (see the AuthSession token, we are using the same token generated for james).

To delete the new admin user:

RestClient.delete 'http://127.0.0.1:5984/_config/admins/david',{:cookies => {"AuthSession" => "b2tlOjRFQUJCNzE0OkXtpl9cxR_zbIxvlvW2J60txIwT"}}

We deleted the admin david, we made the request on behalf of james (see the AuthSession token). If you delete all admins CouchDB will switch back to Admin Party.

To create a non-admin user:

salt = "somerandomstring123"
password = "seenow109"
password_sha = Digest::SHA1.hexdigest(password + salt)
 
user_hash = { :type => "user",
                   :name => "nancy",
                   :password_sha => password_sha,
                   :salt => salt,
                   :roles => []
                  }
 
 
 str = Yajl::Encoder.encode(user_hash)
 
RestClient.put "http://127.0.0.1:5984/_users/org.couchdb.user:nancy", str, {:content_type => :json, :accept => :json}

We created the non-admin user nancy with password seenow109. The above code implements in ruby code the security features explained here. Note that non-admins are authenticated with the same API call as admins.

To create a new database with the authenticated admin user:

RestClient.put 'http://127.0.0.1:5984/contacts', {:content_type => :json},{:cookies => {"AuthSession" => "b2tlOjRFQUJCNzE0OkXtpl9cxR_zbIxvlvW2J60txIwT"}}

We created a new database called contacts. This request was made by the user james, notice the AuthSession token in the request.

To add a security object to the contacts database:

security_hash = { :admins => {"names" => ["nancy"], "roles" => ["admin"]},
                   :readers => {"names" => ["nancy"],"roles"  => ["admin"]}
                  }
security = Yajl::Encoder.encode(security_hash)
 
response = RestClient.put 'http://127.0.0.1:5984/contacts/_security',security,{:cookies => {"AuthSession" => "b2tlOjRFQUJCNzE0OkXtpl9cxR_zbIxvlvW2J60txIwT"}}

The above example uses the yajl-ruby gem to encode the ruby hash to JSON.

To add a new document to the contacts database with the authenticated user session

data = { :name => 'sunny',
         :email => 'sunny@winter.com'
         }
 
 str = Yajl::Encoder.encode(data)
 
 RestClient.put "http://127.0.0.1:5984/contacts/sunny", str, {:cookies => {"AuthSession" => "b2tlOjRFQUJCNzE0OkXtpl9cxR_zbIxvlvW2J60txIwT"}}

We added a document with _id sunny to the contacts database. The above example also uses the yajl-ruby gem for json encoding.

I hope this was helpful. If you find any errors or have suggestions please let me know in the comments.

 
 

It’s just some code you can’t use

06 Jun

Whats the point of Hackathons? You sit down and code for 24 hours. Eat junk food all night, drink lots of soda and red bull. Then end up writing a lot of bad code.

At hackathons, your M.O. is to write code that appears to work, it doesn’t matter how it works. Once you get a feature appear to be working, you move on to code other features. The problem with this type of code is that it doesn’t scale. It makes you feel like you have a working product, but you really don’t. It works fine when you have 10 users but it starts to fall apart when you get to 1000+ users and becomes huge mess when you get to 10000+ users. I think this is a pointless way to build software. You write a lot of code in 24 hours but you end up with a lot of code you can’t use later. You also learn a ton of bad coding habits.

The best thing to do at a hackathon if you must go, is to socialize with people while you work on your long term side project. Its a great place to meet new people and share ideas with them but not the place start and finish something useful.


At the Techcrunch Disrupt hackathon.

 

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.

 

Routes in Rails 3

25 Mar

This is cool stuff. Nuff said. See more here: http://www.engineyard.com/blog/2010/the-lowdown-on-routes-in-rails-3/

 
 

Installing Ruby 1.9.2 & Rails 3 on Ubuntu with a single command

07 Mar

I wrote a script that installs Ruby 1.9.2 with RubyGems, Rails 3 and sqlite on Ubuntu with a single command. This script makes it very easy to get started developing Rails applications on Ubuntu. Its also an easy way for non-ruby developers to run popular Rails applications.

This is a script I originally wrote, a while ago for Ruby 1.8.7 and Rails 2, I recently realized that most of the traffic coming to my blog were people looking to setup Rails on Ubuntu. So I decided to update the script for Rails 3 and Ruby 1.9.2. So please enjoy.

I remember about 2 years ago, when I got kicked out of a shared hosting account because I was using too much CPU time, I was forced to move my high traffic web service to EC2. I was still new to Linux, it was my first time deploying a Rails app in production, and I was going to go live with thousands of users instantly. It was a nightmarish weekend. That’s why I write scripts like this, to help new users from Windows and OS X get comfortable with the Linux world.  Although Ubuntu 10 is much easier than 8.10, and Ruby 1.9.2 is a big improvement, Rails 3 with bundler is also a big relief, this is a script I wish I had 2 years ago while deploying my first Rails app.

Assumptions Made by the script

The script assumes you don’t have an older version of Ruby like (1.8.7) installed on the system. If you already have an older version of Ruby installed, use RVM instead of this script. To check if you have an older version of Ruby installed type

ruby -v

Installing and setting up Rails with a single command

Step 1: Install Git if you don’t already have it

 sudo apt-get install git-core

Step 2: Download the script from Github

 git clone git://github.com/obi-a/speedtrain.git

Step 3: Change to the speedtrain directory (the script is called speedtrain)

 cd speedtrain

Step 4. Make the script executable

 chmod +x speedtrain

Step 5. Run the script

 ./speedtrain

This will install Ruby 1.9.2,RubyGems, Rails 3 and Sqlite. It will create a folder in your $HOME directory for your Apps called rails_apps. It will also create a sample Rails App called testapp.

To run the sample Rails app. Type…

 cd $HOME/rails_apps/testapp
 rails server

To view the app, open a browser and type http://localhost:3000/

To create a new Rails app. Type..

 cd $HOME/rails_apps
 rails new myapp

Who should use this script

  • Rubists from MS Windows and OS X getting into Ruby/Rails/Linux
  • Non-Rubists that need to run Rails apps on Ubuntu
  • Newcomers to the Ruby/Linux World
  • Rubists that only need Ruby 1.9.2

Related Posts:

Ubuntu, Ruby, RVM, Rails and You

Source code for the script: https://github.com/obi-a/speedtrain/blob/master/speedtrain

 
 

Installing Ruby 1.9.2 on FreeBSD

06 Jan

I’m new to FreeBSD and I’m really loving it. As a Ruby developer here’s how to get started with FreeBSD.

Some things you might need, before you install Ruby
FreeBSD comes with csh by default, which is fun but its a bit cryptic. You might want to simply use the bash shell. The following installations may take a long time to complete because we are building everything from source.

To Build and install Bash

# whereis bash
bash: /usr/ports/shells/bash
 
# cd /usr/ports/shells/bash
# make install clean

To use bash, type:

# /usr/local/bin/bash

To make bash the default shell:

# chsh -s /usr/local/bin/bash {username}
# chsh -s /usr/local/bin/bash obi

To Build and Install wget

# whereis wget
wget: /usr/ports/ftp/wget 
 
# cd /usr/ports/ftp/wget
# make install clean

To Build and install python
We will need Python to build Git later.

# whereis python
python: /usr/ports/lang/python
 
# cd /usr/ports/lang/python
# make install clean

To Build and install Git
Git source mirror.

# wget http://www.kernel.org/pub/software/scm/git/git-1.7.3.4.tar.gz
# tar xzf git-1.7.3.4.tar.gz
# cd git-1.7.3.4
# ./configure
# gmake
# gmake install
 
#git version
git version 1.7.3.4

To Build and install Ruby 1.9.2

# wget ftp://ftp.ruby-lang.org//pub/ruby/1.9/ruby-1.9.2-p136.tar.gz
# tar xzvf ruby-1.9.2-p136.tar.gz
# cd ruby-1.9.2-p136
# ./configure
# make install
 
# ruby -v
ruby 1.9.2p136 (2010-12-25 revision 30365) [i386-freebsd8.1]
 
# gem -v
1.3.7
 
# irb -v
irb 0.9.6(09/06/30)

We are all set. We now have the same Ruby environment on BSD as we use on Linux. I used this setup to test Ragios on FreeBSD. Bundler installed all the required gems with no problems.

If I missed something something in this write-up, please let me know in the comments.
Happy New Year!

 
 

Moving an old Rails 2 App to a New Server Using Bundler

04 Dec

I’ve had this Rails 2.3.2 app running on an Amazon EC2 small instance since March 2009. The app does some back-end processing for the media player software I created for SecondLife. The App stack is nginx, Rails 2.3.2, and some Mongrels. I decided to switch to a micro instance. This will cut my monthly bill from $60 to around $15. The 613MB RAM available on the micro-instance should be more than enough for my app. Amazon also just announced free basic resource monitoring for EC2 instances which means i can easily monitor resource usage to be sure my app isn’t running out of resources.

Packaging Rails Apps with Bundler
I first discovered Bundler while looking for an easy way to deploy Ragios. Ragios now uses Bundler for dependency management. With bundler I can just package my Rails app with all its dependencies (gems) and copy it to a new system. Bundler will install the right version of all the rubygems required for my app to run on the new system.

This is how I used it;

On the old Server
First install the Bundler Rubygem

sudo gem install bundler

Change directory to the root of your rails app

cd myapp

Create a GemFile for your rails app

bundle init

The Gemfile is created in the root directory of your rails app.
Edit the Gemfile and add the gems used by your app.

Example,

gem "rails"

or

gem "rails" , "2.3.2"

Include version number if you want bundler to use a specific version of the gem.

In my case, I wanted every gem on the new server to be exactly the same version as the gems on the old server. So I added version numbers for each gem.

If you want to list all the gems on your system to see their version number, run the ‘gem list’ command;

gem list

Below is a copy of my Gemfile:

source "http://rubygems.org"
 
gem "rails", "2.3.2"
gem "hpricot","0.8.1"
gem "simple-rss","1.2"
gem "rake","0.8.7"
gem "mongrel","1.1.5"
gem "mongrel_cluster","1.0.5"

You don’t need to add every gem on gem list to your Gemfile. You just need the gems you installed and required on your app. Bundler will detect the rest and install all dependencies. Example activesupport, actionmailer etc. will be installed by Bundler for the Rails gem.

Next ;

sudo bundle install

With this command, bundler will download and install all the listed gems and their dependencies. If you already have the gems installed on your system, bundler will use the one you already have. Below is the output from running bundle install with my Gemfile;

Fetching source index for http://rubygems.org/
Using rake (0.8.7) 
Using activesupport (2.3.2) 
Using actionpack (2.3.2) 
Using actionmailer (2.3.2) 
Using activerecord (2.3.2) 
Using activeresource (2.3.2) 
Using cgi_multipart_eof_fix (2.5.0) 
Using daemons (1.1.0) 
Using fastthread (1.0.7) 
Using gem_plugin (0.2.3) 
Using hpricot (0.8.1) 
Using mongrel (1.1.5) 
Using mongrel_cluster (1.0.5) 
Using rails (2.3.2) 
Using simple-rss (1.2) 
Using bundler (1.0.7) 
Your bundle is complete! Use `bundle show [gemname]` to see where a bundled gem is installed.

When you run bundle install, it will creates a file Gemfile.lock, this file contains a map of all your gems and their dependencies. Bundler will use this file to install gems on the new server.

Now copy the entire directory of your rails app to the new server. Make sure you have Gemfile and Gemfile.lock in the root directory of your Rails app when you copy it to the new server.

On the new server
With your Rails app now copied to this server,

Install bundler

sudo gem install bundler

Change directory to the root of your rails app;

cd myapp

Run bundler to download and install the gems required for your rails app to run on this server

bundle install

After this, your Rails app is ready to run on the new server. You can test it with WEBrick.

I then installed Apache and Phusion Passenger.

Ruby has come a long way, it took only a few minutes to move the app from the old server and setup it up on a new server.

You can see I also switched the app from nginx/mongrels to Apache/Passenger.

There are other ways to use bundler with Rails 2.3, since this is the only Rails app I plan to run on this server, I simply needed Bundler to install the right version of all my gems globally in the system for MRI to use.

Hope this was helpful.

More info on Bundler here.

 
 

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

 
 
Premium Wordpress Plugin