preload
Using a Class as an Array in Ruby Perl Connectivity Check Script
Apr 07

Every once and a while I get too fancy for my own good. :) A customer of mine has lots and lots (well…hundreds really) of Unix hosts that need updates of config files and such. There are lots of tools out there that can do what I need to do, but they all require an install on the nodes themselves. My customer does not want any extra software on these nodes, so to do any kind of automation requires me to upload the program, run it remotely, then remove it. I have a large number of tools to do all that several different ways.

Recently though, I needed to download a large file from each node while running another program on the node at the same time. Normally I would use SCP for the download part, but for reasons that would take too long to explain, that option was not open to me. So for some reason, I was struck with the ideal to just use a custom XMLRPC client/server to do the job. Turns out the code is pretty simple. My customer only has Python on these nodes, so my XMLRPC client is written in Python:

#
# xmlxfer.py
#
import xmlrpclib
import sys
import platform

port = 80    # Some port that passes through your firewall:  80, 21, 23, 25, etc.

farfname = sys.argv[1]
localfilename = sys.argv[2]
server = sys.argv[3]
#host = platform.uname()[1]
host = platform.node()
farname = host + "-" + farfname

ff = open(localfilename, "r").read()

svr = "http://" + server + ":" + port + "/RPC2"
xmlprxy = xmlrpclib.ServerProxy(svr)

print xmlprxy.xfer(farname, ff)

The program prefixes the hostname to the file name, so that if I’m downloading a large number of files, they won’t overwrite any of the other files (assuming your hostnames are all different — and they should be!). It sets up the XMLRPC server proxy, then calls the Remote Procedure Call (RPC) “xfer” with the name of the file, and a string buffer holding the contents of the local file. It is called like so:

>python xmlxfer.py apache_access.log /var/www/logs/access.log spinebreaker.z2u.info

The server side is written in Ruby (since I have more control over what I use on my side of the network).

#!/usr/bin/ruby
#
# xml_file_xfer_svr.rb
#

require 'webrick'
require 'xmlrpc/server.rb'

def filesave(fname, buf)
  f = File.open(fname, "w")
  f.write(buf)
  f.close
  puts "File #{Dir.pwd}/#{fname} has been saved."
  "OK"
end

# create a servlet to handle XML-RPC requests:
servlet = XMLRPC::WEBrickServlet.new
servlet.add_handler("xfer") { |fname, buf| filesave(fname,buf) }

# create a WEBrick instance to host this servlet:
server=WEBrick::HTTPServer.new(:Port => 23)
trap("INT"){ server.shutdown }
server.mount("/RPC2", servlet)
server.start

Again, very simple code. The ‘xfer’ RPC calls the ‘filesave’ method, which does a simple file write. Note that it returns ‘OK’, as you need to return something for the RPC call, or you will get a parameter error on the client when nothing is returned.

I could have used a SOAP/HTTP setup as well, but SOAP was kind of overkill for just transferring files. I have a post about using a Ruby SOAP client to a Perl SOAP Server on another blog of mine if you are interested.

SociBook del.icio.us Digg Facebook Google Yahoo Buzz StumbleUpon

Leave a Reply