Friday, June 20, 2008

HOWTO: Display a Custom Boot Message for Your VMWare Appliance

So I'm building a VMWare appliance for Stratavia's Data Palette data center automation application, and I want it to be like all the other cool appliances that print out some system-specific configuration information (e.g., IP address) when it finishes booting. This is useful for when, say, your appliance runs a webapp via an HTTP server like Apache or Mongrel or Tomcat and you want to tell the user where to point his browser to see it in action.

I happen to be using the latest Ubuntu JEOS as the base OS for this appliance. As such, in order to hook in to the boot process, I am adding my changes to the /etc/rc.local file.

(Author's Note: The exact location and name of this file vary -- sometimes wildly -- between Linuxen. Some flavors use /etc/rc.d/rc.local. Gentoo uses /etc/conf.d/local.start. I paraphrase the immortal Daffy Duck in "The Scarlet Pumpernickel": "Fancy, thy name is Linux. To coin a phrase.")

Let's say you want your user to visit http://[whatever the IP address ends up being] following bootup to get the virtual ball rolling. But you don't know what that IP address will be when you bundle your appliance; it's going to be assigned dynamically at bootup (as it should be). No problema. Simply write a bit of script to scrape the IP address in your Linux flavor's version of rc.local, thusly (Note: The following bit of awesome is directly ripped off from the rc.local file of the MindTouch Deki Wiki appliance):
IP=`ifconfig eth0 | grep "inet addr" | awk -F ' ' '{print $2}' 
| awk -F ':' '{print $2}'`
If you're Richard Stallman or some other Unix guru and you already know what the heck all this does, you can just smile smugly and skip the next few paragraphs. For the rest of us:

ifconfig eth0 -- Run the system command ifconfig to print out the general networking information for this box (specifically, the first ethernet interface), and send ("pipe") its output to the grep command. The output for ifconfig eth0 will look something like this:

eth0      Link encap:Ethernet HWaddr 00:0c:29:2d:f7:73
inet addr:172.16.139.130 Bcast:172.16.139.255 Mask:255.255.255.0
inet6 addr: fe80::20c:29ff:fe2d:f773/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
[et cetera]


There are several more lines, but all we care about is the second line. The next command in the chain, grep "init addr", will filter out all the stuff we don't want, leaving us with just the second line. This is then fed to the first of two awk scripts.

The first awk script uses a field separator of "space" (-F ' '); this splits the inet addr line into its constituent "words", like "inet" and "addr:172.16.139.130". We just want the "addr:" word, so we print it as the output of the first awk script and send it to the second ({print $2}).

The second awk script splits its input using the colon as its field separator (-F ':') and prints the second word, which is -- tada! -- the IP address of the virtual machine. Whew.

The Rubyistas reading this blog (assuming I have any left) may have downloaded Ezra Zygmuntowicz's way-cool EngineYard Express VMWare image. Its bootup a little more involved, asking for input from the user on initial boot, and displaying several bits of information after every boot thereafter, such as the randomly-generated root and express user passwords. EY Express is running on Gentoo, so its startup hook is in /etc/conf.d/local.start.

EY being EY, they delegate all the heavy lifting to Ruby via some custom Ruby Gems: ey_reporter, config_system, and system. You have to do some serious filesystem spelunking to get there, but you can find the Ruby code that figures out the IP address (the equivalent of the bash script above) in
/usr/lib/ruby/gems/1.8
/gems/system-[version]/lib
/system/info/info.rb

4 comments:

Unknown said...

Awesome. Thanks!

David Rupp said...

Hi, Gregory. Glad this was helpful for you. :-)

Unknown said...

That should be /etc/rc.local. Thanks for the tips!

David Rupp said...

Of course it should be. Man, that typo's been out for most of a year now; thanks for catching it!