Cover V13, i04

Article

apr2004.tar

Python in Systems Administration: Part V -- Python Networking

Cameron Laird

Python makes network administration scriptable, which is a wonderful thing. As Unix systems administrators, our responsibilities reach beyond configuration of a single host. We also cultivate and repair the whole range of client-server networking that underlies early 21st-century computing. Too many times, though, we try to do this job with end-user applications that are clumsy for our needs. There's a better way.

For example, a few years ago, I was in a cycle of upgrading email services. At first, I could only define project goals in terms of the end-user experience. If a networked end-user could retrieve her inbox with an acceptable delay, then I declared the POP3 service good.

Opening the Hood

That's a perfectly appropriate target, but it's a mistake to confuse the criterion with the diagnostic method. Think of the task of automobile repair. When an owner complains that his car bucks around 44 mph, a test drive has to validate any remedy. That doesn't mean the way to fix the car is to cruise around until inspiration descends. Instead, a good mechanic brings the car into the shop, opens up the hood, and breaks down the problem into possible component causes.

We need to do the same. Don't let the wrapping of user interfaces prevent you from seeing the problems and root causes inside them. When I started the upgrade cycle, I knew little more about POP3 than how to configure a particular Netscape email client to a particular email server. That scales poorly. Diagnosing and validating POP3 for an entire user community that way is clumsy and time-consuming.

So I came up with better ways. I wrote tiny little scripts that helped me monitor server operations quicker and more precisely, and others that tested clients and networks. These scripts paid off in a big way. When a user reported an outage, I could check his or her mailbox and connectivity in a few seconds, rather than the couple of minutes it took me to bring up a Netscape, save its configuration, define a new account, try out a download, read the result, and restore my Netscape.

Scripting's a good idea, one that deserves to be understood more widely. One reader, Patrick Rateleff, responding to an earlier installment of this Python series, wrote: "The hardest thing I have found ... is not the OS or understanding things, but thinking about problems differently, knowing that I can develop my own solutions that function. In the past ... I would look for a shareware or commercial application that addressed the issue. ... I start to see how much more I could do."

Many Unix scripters, though, think in terms of the Bourne shell and its immediate descendants. With sh, scripting generally "glues" together external processes that do "real" work, especially in networking. That can be handy, just as off-the-shelf solutions have their place.

Python Expands Possibilities

Python opens up a whole new domain of scripting, however, particularly for networking problems. Python builds in a full range of networking functionality, including knowledge of such standard protocols as FTP, POP3, and IMAP4, as well as low-level socket-oriented programmability.

This is a remarkable achievement, and just think what it means. As earlier articles in this series have shown, Python scripting is as easy to learn as sh. If you have a need, though, you can move far beyond sh's capabilities, all the way to the low-level precision usually associated with C. If any computer application can do a particular task, a Python-coded application can probably do that task, too, with all the productivity and maintainability of a high-level language. Only a few requirements -- principally raw computing speed -- disqualify Python.

How easy is Python networking? Here's a basic POP3 "inspector":

import poplib

account = "XXX"
password = "XXX"
host = "mail.XXX.XXX"
pop = poplib.POP3(host)
pop.user(account)
pop.pass_(password)

print "This mailbox has %d messages, totaling %d bytes." % pop.stat()
Judge for yourself how easy this is. The standard Python Library Reference chapter on "Internet Protocols and Support" demonstrates that Python makes other networking standards as accessible as POP3. The reference is available at:

http://python.org/doc/current/lib/internet.html
Low-Level Sockets

Full coverage of Python networking extends to low-level socket programming, most accurately introduced in Gordon McMillan's "Socket Programming HOWTO", which is available at:

http://www.amk.ca/python/howto/sockets/
I recommend "Internet Protocols..." first, though, for a couple of reasons. First, protocol-level support is far likelier to match most systems administration chores in my experience. Second, "raw" sockets are more of a development than administrative concern.

When administrators do need to move outside the defined network protocols, I think interfaces slightly higher than those of the "HOWTO" serve us best. I'm a big fan of the asyncore module:

http://www.python.org/doc/current/lib/module-asyncore.html
and, even more, the Twisted networking framework:

http://www.twistedmatrix.com/products/twisted
These have all the power of low-level sockets, but are packaged in a way that makes it easier to write correct programs. With Twisted, for instance, all it takes to write a minimal "echo server" is:

class Echo(protocol.Protocol):
    """This is just about the simplest possible protocol"""
  
    def dataReceived(self, data):
        "As soon as any data is received, write it back."      
        self.transport.write(data)
  
def main():
    """This runs the protocol on port 8000"""
    factory = protocol.ServerFactory()
    factory.protocol = Echo
    reactor.listenTCP(8000,factory)
    reactor.run()
  
# this only runs if the module was *not* imported
if __name__ == '__main__':
    main()
This is copied directly from the Twisted example page:

http://www.twistedmatrix.com/documents/examples/
whose other programs are almost equally easy.

Scripter's Attitude

The most important knowledge this series can give is the high-level attitude of a proficient Python scripter: if there's a computing job to be done, there's probably a good way to do it with Python. This truth shines brightest on networking, because other languages handle sockets either with difficulty, or not at all, while Python networking is succinct and sensible.

Cameron Laird, a vice president at consultancy Phaseit, Inc. (http://phaseit.net/), has written occasionally for Sys Admin in previous years.