Home Home > 2009 > 01 > 14 > Using Ruby for system scripts
Sign up | Login

Using Ruby for system scripts

January 14th, 2009 by

So here we are, the second installment of my openSUSE+Ruby mini-series.  See this link for the first article covering installation and configuration.  In this post, I’ll give you a fast introduction to Ruby and a sample system script on openSUSE.

Super-quick intro to Ruby syntax

So first and foremost, I suppose we should start with some basic Ruby syntax.  I’m going to keep this brief, so for a more proper introduction, see http://ruby-lang.org.

To get your feet wet, lets fire up ‘irb’, the Ruby interpreter and get the standard Hello World program out of the way:

irb(main):001:0> puts “Hello, World!”
Hello, World!
=> nil

Here we see the method ‘puts’ displaying our string followed by the result of the expression.  This is pretty straightforward stuff.  So lets move on to some more useful stuff: variables, modules, methods (we’ll leave classes out for now), and iteration:

Variables are extremely straightforward, just use your ‘=’ operator to create a variable.  Ruby is dynamically typed so we don’t have to declare our variables prior to creating them.  For more on this, check out “Duck Typing”.  Lets assign a variable and print it out:

irb(main):002:0> n = 42
=> 42
irb(main):003:0> puts n
42
=> nil

Easy, right?  Lets keep this whirlwind intro moving, then.  On to Modules, Ruby comes with tons of modules that are available right at your fingertips.  You can find documentation for Ruby modules at http://ruby-doc.org or pick up a reference book (my personal favorite is the “pickaxe book“).

Modules are called simply by Modulename.method(args).  Here’s a quick example using our previously defined variable:

irb(main):004:0> Math.sqrt(n)
=> 6.48074069840786

Here, we called the sqrt method of the Math module on our variable.  Also note that it automatically converted the type for us.  We’ve gone from an integer to a floating point number without any voodoo on our part.

I don’t have time in this article to cover Classes (see your favorite reference/tutorial for more info on classes), but methods are relatively simple to define.  Lets put our ‘Hello, World’ code into a method.  Just to mix things up, lets toss a variable in as well:

irb(main):005:0> def howdy(name = “World”)
irb(main):006:1>   print “Hello, #{name}!\n”
irb(main):007:1> end

Now we can simply call our method ‘howdy’ with or without arguments:

irb(main):008:0> howdy
Hello, World!
=> nil
irb(main):009:0> howdy “Geeko”
Hello, Geeko!
=> nil

Yet another useful thing we may be interested in is iteration.  While iteration looks a little different in Ruby, it’s relatively simple.  You may be used to the simple ‘for i in foo; do bar; done’ syntax of most languages.  Ruby mixes that up a little…

Here I’ll define an array and iterate over each element.  Watch closely:

irb(main):015:0> pals = %w{Tux Geeko Linus}
=> ["Tux", "Geeko", "Linus"]
irb(main):016:0> pals.each do |i|
irb(main):017:1*   puts “#{i} is my homeboy!”
irb(main):018:1> end
Tux is my homeboy!
Geeko is my homeboy!
Linus is my homeboy!
=> ["Tux", "Geeko", "Linus"]

Here you can see we stepped through each element of the array ‘pals’ and displayed said element with a message.  It may look wacky now, but the more you use it, the more natural it becomes.

So you want to automate some tasks?

When using Ruby with openSUSE, the sky is the limit with system automation.  To call system commands, simply use backticks (`) just as you would in bash or your favorite shell.  The simple syntax encourages rapid development, so Ruby is a great language for working with your servers.
One thing I do frequently is check for updates across my servers and mail them back to myself.  This requires that we install the ruby gem ‘mailfactory’ (‘sudo gem install –remote mailfactory’) so that we can spawn an SMTP server.

We probably all use zypper to search for updates, so here’s a simple script that will check for all updates on a box and mail it right to you.  Note that this is a very simplified version of part of a larger collection of scripts that I use daily to monitor my servers…

#!/usr/bin/env ruby
# be sure to include all necessary modules

require ‘rubygems’ # necessary to use mailfactory
require ‘net/smtp’ # another mailfactory requirement
require ‘mailfactory’

# this method has zypper search for updates and save them to a variable
# note that we could alternatively search for zypper’s path and store it in
# a variable as well

def zypper (option)
zypper_output = `”/usr/bin/zypper” #{option}`
return zypper_output
end

# call the zypper method. note that ‘lu’ lists updates in zypper

zypper_msg = zypper(“lu”)

# call Net::SMTP to fire up a server
smtp = Net::SMTP.new(‘localhost’, 25)
smpt.start(‘yourserver.com’)

# craft our message
report = MailFactory.new()
report.to = “admin@yourserver.com”
report.from = “admin@yourserver.com”
report.subject = “server updates”
report text = “#{zypper_msg}”

# send our message
smtp.send_message report.construct, ‘admin@yourserver.com’, ‘admin@yourserver.com’
smtp.finish

While the last portion of that (MailFactory) got kind of messy, the script is relatively simple to step through.  First we add all the necessary gems/modules to help send our message, then we define a method that calls zypper.  After we’ve established that, we simply pass our options (in this case, list updates) to the zypper method and mail it out.

The same can be done to interact with system utilities to perform maintenance, parse logs, or gather more information.  Take a look at the File module and browse through some gems, you’ll very likely find plenty of useful utilities.  Use your imagination and by all means, enjoy yourself!

Stay tuned for my next post in which I’ll cover remote automation with Capistrano.

Both comments and pings are currently closed.

2 Responses to “Using Ruby for system scripts”

  1. drboolean

    Don’t mean to be a stickler, but someone might really get stuck on this.

    works:
    def zypper (option)
    “\”/usr/bin/zypper\” #{option}”
    end

    doesn’t:
    def zypper (option)
    zypper_output = `”/usr/bin/zypper” #{option}`
    return zypper_output
    end

  2. Good eye!

    I didn’t copy and paste this from the script I originally pulled it from because of the strange formatting in WordPress. I got in a bit of a hurry and jumped ahead of myself here.

    I also just noticed that my indenting didn’t stick with the post, I’ll have to fix that somehow.

    Thanks for the correction!