Wednesday, April 7, 2010

Using Ruby with Zenoss - Part 2

This is the second installment of Using Ruby with Zenoss.  This posting will mainly focus on using the library.  If you have not read Part 1, I would strongly recommend going there first in order to make sure your environment is set up correctly.

In creating the Zenoss library for Ruby I have tried to keep the interface to the programmer fairly similar to the Python API.  It is somewhat simplified because the depth of modules and classes don't map one-for-one to a REST client world.  There is still much to be in its implementation, but here are a few examples of what you can do with the library today.



Requiring the gem

!!! You need to have at least version 0.0.4 of the gem installed. !!!

Make sure you add this to any of the following examples:
require 'rubygems' # if you're using gems
require 'zenoss'

Getting Started

You need to tell zenoss_client where to point and how to authenticate. To do that use the following code:

# Set the base uri that we talk to Zenoss with. Your host will
# be unique but the port will probably be 8080 unless you proxy
# it through 80.
Zenoss.uri 'https://:/zport/dmd/'

# Add the appropriate credentials
Zenoss.set_auth('user','pass')

Getting a list of devices

Now that we're set up we can get down to it. One of the primary things that I find myself doing is managing devices through the REST interface. You need a starting point so let's get the base Device class ( /zport/dmd/Devices ):

devices = Zenoss.devices

You can think of the 'Zenoss' object as a slimmed down equivalent of 'dmd' in the zendmd Python interface.

If you want to start at a DeviceClass deeper in the tree you can do so by passing the path to DeviceClass:

linux = Zenoss::Model::DeviceClass.new('/Devices/Server/Linux/')

Once you have your DeviceClass you can list the devices beneath it like so:

subdevs = linux.get_sub_devices

Device Info

Using the Device Array from the last step, we'll take the first device and get some information from it.

mydev = subdevs.first

# Get the status id
mydev.get_status

# Get the icon associated with this status
mydev.get_status_img_src(mydev.get_status)

# Get uptime
mydev.sys_uptime

# Fetch some RRD Values
dps = mydev.get_rrd_data_points
dsnames = []
dsnames << dps[1].name
dsnames << dps[2].name
mydev.get_rrd_values(dsnames)
# => {"laLoadInt1_laLoadInt1"=>"252.27000000000001", "laLoadInt15_laLoadInt15"=>"255.86000000000001"}

Systems

The library has basic support for Systems now. It's mainly just the ability to create and delete subsystems. More support is forthcoming.

# Fetch the base '/Systems' System
systems = Zenoss.systems

# Create a new subsystem
ltst = systems.add_subsystem('linuxtst')

# delete the newly created System
ltst.delete!

That's it, go play

That's a quick introduction to the Zenoss Ruby library. I'm adding new functionality all the time so check for updates often. The code is up on github at http://github.com/zenchild/zenoss_client so if you want to fork it and help out with development you're welcome to do so. If you're not interested in developing it but would like to see a feature added please comment below or open up a ticket on github and I'll get to it as time allows. I hope you find the library useful.

Addendum: The RDocs are available at http://rdoc.info/projects/zenchild/zenoss_client

Cheers,

Dan

Thursday, April 1, 2010

Using Ruby with Zenoss - Part 1

I have been using Zenoss now for over a year and for the most part have been quite happy with it. It's quite customizable and you can find a way to pretty much monitor anything if you put some thought into it. However, my one point of contention has been with the REST interface. Most things work as you would expect, but somethings blow up and don't give you a very good reason except for a nice Zope stack-trace.  Prior to using Zenoss, I had very little experience with Zope so some of my issues were simply just lack of knowledge of how REST methods were called from within it.  I wrongly thought that there was a translation layer that sat between the web user and the back-end to marshal and unmarshal datatypes.  This does not seem to be what is going on.  So if I can sum up all of the issues that I struggled with it's this:
  •  If the Python method you're calling on the back-end is expecting something other than a string you're probably going to have issues.
So, coupled with my poor knowledge of Zope and my frustration on how to call REST methods in a consistent way, I decided to create a library for Zenoss in Ruby.  My goal was to create that middle layer to correctly marshal and unmarshal data-types.
I chose Ruby because I find it a fun language to program in and well, I guess that pretty much sums it up ;-)
 In order for the library to work there is one thing that you need to do on the Zenoss/Zope side.  To marshal data-types into Python you most certainly need to do it in Python so we have to add a custom script to Zope.
  1. Go to the Zope Management page:
    • http://zenoss:8080/zport/dmd/manage
  2.  Select "Script (Python)" from the upper-right drop-down
    • ID = callZenossMethod
      • "Add and Edit"
    • Title = "Work around for unsupported Zenoss methods"
    • Parameter List = methodName
    • Clear out the code contents from the text box and cut-and-paste the code found here:
    • "Save Changes"
Once the custom Python is in place simply install the ruby gem:
  • gem install -r zenoss_client
That's it, you should be ready to roll.  Check back here soon for the second part of this post for example usage of the zenoss_client library.



addendum: Link to zenoss_client source code: zenoss_client