Query Your Applications Using IRC

March 02, 2009

IRC — most of you know what it is. For those who don't, it stands for Internet Relay Chat. Think of it as a geeky group chat and you won't be far off.

There's a long tradition of using bots — automated processes — to provide services in IRC channels. Bots that help people share code through Paste Bin services, bots that take messages for offline users and replay them later. They're genuinely useful because they enhance a communication medium that people are already using, without requiring any extra software on the client side.

Last.fm use IRC as an internal communication tool. They've written (and released under the GPL — thanks!) IRCCat, which makes it straightforward to build bots that answer queries or perform commands right from IRC channels.

I've set up IRCCat and written a few scripts for it. Getting started is pretty easy. You'll need Java and Ant installed. I'm on a Mac with OS X 10.4, so Java is already there, and MacPorts provides an Ant port.

With Java and Ant ready, clone the IRCCat source from GitHub:

git clone git://github.com/RJ/irccat.git

Compile and package the bot by running ant dist in the cloned directory.

Once it's packaged, create a config/ directory and copy the example configuration from examples/irccat.xml into it. This is where you tell the bot how to behave.

The config file is reasonably well commented. Walk through each section and fill in the details:

  • Provide your IRC server connection details. I use an internal server, but if you don't have one, there are plenty of public IRC networks a quick search away.
  • Set the bot's username.
  • Change the external scripts handler to scripts/run and bump the max response lines to 30.
  • Choose which channels the bot should join. If they don't exist, they'll be created when the bot joins (depending on network policy).

With the configuration done, launch the bot:

ant -Dconfgfile=./config/irccat.xml

If you're in one of the channels you told it to join, you should see it appear. Verify it's working by typing !channels:

CraigW: !channels
bot: I am in 2 channels: #foo #bar

There are a few built-in commands, all prefixed with an exclamation mark:

Command Description
!join #channel password Make the bot join a channel (password is optional)
!part #channel Make the bot leave a channel
!channels List all channels the bot is in
!spam message Send a message to all channels
!exit Shut down the bot

The really interesting part is external commands, triggered with a question mark prefix. You write these yourself, and they can do anything you want.

Remember the cmdhandler config value I set to scripts/run? That's the entry point for externals. I use it to launch a router that loads and executes other command scripts from the scripts/ directory.

My scripts/run looks like this:

#!/bin/bash
# This script handles ?commands to irccat

exec ruby ./scripts/router "$@" 2>&1

Make that executable (chmod +x scripts/run). The scripts/router handles the dispatch:

#! /usr/bin/env ruby

COMMANDS = File.expand_path(File.dirname(__FILE__))
name, channel, username, command, arguments = *ARGV[0].split(/ /, 5)

command_script = File.join(COMMANDS, File.basename(command))

if File.exists?(command_script) && !%W(run router).include?(command)
  load command_script
  puts Command.execute(name, channel, username, arguments).strip
else
  desired_command = "#{command} #{arguments}".strip
  puts "Sorry #{name}, I don't understand `#{desired_command}`."
end

Writing a new command is now just a matter of creating a script that implements a Command class. The filename determines what you type in IRC. Want to query SNMP on a host? You'd type something like ?snmp xeriom-vm-host-06 .1.3.6.1.2.1.1.1, so the script goes in scripts/snmp:

class Command
  class << self
    def execute(name, channel, username, arguments)
      hostname, oid, remainder = arguments.split(/ /, 3)
      `snmpwalk -c public -v 1 #{hostname}.core.xeriom.net #{oid}`
    end
  end
end

Type the command in IRC and the results come straight back. No bot restart needed:

CraigW: ?snmp xeriom-vm-host-06 .1.3.6.1.2.1.1.1
bot: SNMPv2-MIB::sysDescr.0 = STRING: Linux xeriom-vm-host-06.core.xeriom.net 2.6.24-17-xen #1 SMP Thu May 1 15:55:31 UTC 2008 x86_64

There's real power in having this kind of access right inside your team's communication channel. A quick command can pull up customer records, server stats, or application data without anyone needing to drop to a terminal or load a web page.

Ruby vs Java

I've since discovered a Ruby port of IRCCat. I'll be switching to that — I find Ruby projects easier to maintain and fork than Java ones. Your mileage may vary.

Questions or thoughts? Get in touch.