Code critique xmlrpclib

flagg ianand0204 at gmail.com
Mon Feb 2 21:25:37 EST 2009


This xmlrpc server is designed to parse dns zone files and then
perform various actions on said files. \
It uses dnspython, and xmlrpclib
 I'd like to know what some of the more experienced python users
think. Where I could improve code, make it more efficient, whatever.
All suggestions are welcome.  This is my first functional python
program,  and I have tons of questions to go along with whatever
suggestions.   How could I do sanity checking; right now nothing
checks the input to these functions, error-handling in this program is
almost non-existant how do you integrate decent error handling into a
piece of software......ill shut up now.

Thanks


import dns.zone
from time import localtime, strftime, time
import os, sys
from dns.rdataclass import *
from dns.rdatatype import *
from string import Template
import xmlrpclib
from SimpleXMLRPCServer import SimpleXMLRPCServer
from SimpleXMLRPCServer import SimpleXMLRPCRequestHandler


zoneDir = "/dns"

def openZoneFile(zoneFile):
    """
    Opens a zone file.  Then reads in zone file to dnspython zone
object.
    """
    global zone
    global host
    global domain
    domain = ".".join(zoneFile.split('.')[1:])
    host = ".".join(zoneFile.split('.')[:1])

    try:
            zone = dns.zone.from_file(zoneDir + domain + '.zone',
domain)
    except dns.exception, e:
            print e.__class__, e

class DNSFunctions:

     # Not exposed to xml-rpc calls, used internally only.
    def _writeToZoneFile(self, record):
        """
        Checks if zone file exists, if it does it write values to zone
file
        """

        for (name, ttl, rdata) in zone.iterate_rdatas(SOA):
            new_serial = int(strftime('%Y%m%d00', localtime(time())))
            if new_serial <= rdata.serial:
                new_serial = rdata.serial + 1
            rdata.serial = new_serial

        if os.path.exists(zoneDir + str(zone.origin) + "zone"):
            f = open(zoneDir + str(zone.origin) + "zone", "w")
            zone.to_file(f)
            f.close()
        else:
            print "Zone: " + zone.origin + " does not exist, please
add first"

    def showRecord(self, record):
        """
        Shows a record for a given zone. Prints out
        TTL, IN, Record Type, IP
        """

        openZoneFile(record)

        try:
            rdataset = zone.get_node(host)
            for rdata in rdataset:
                return str(rdata)
        except:
            raise Exception("Record not found")


    def changeRecord(self, record, type, target):
        """
        Changes a dns entry.
        @param record: which record to chance
        @param type:  what type of record, A, MX, NS, CNAME
        @target: if CNAME target points to HOSTNAME, if A record
points to IP
        """
        openZoneFile(record)
        try:
            rdataset = zone.find_rdataset(host, rdtype=type)
        except:
            raise Exception("You must enter a valid record and type.
See --usage for examples")

        for rdata in rdataset:
            if rdata.rdtype == CNAME:
                rdata.target = dns.name.Name((target,))
            elif rdata.rdtype == A:
                rdata.address = target
            else:
               assert False

        self._writeToZoneFile(host)


    def deleteRecord(self, record):
        """
        Delete Entry from zone file
        """
        openZoneFile(record)
        zone.delete_node(host)
        self._writeToZoneFile(record)

    def addRecord(self, record, type, target):
        """
        Adds a new record to zone file
        """
        openZoneFile(record)

        rdataset = zone.find_rdataset(host, rdtype=type, create=True)
        if rdataset.rdtype == A:
            rdata = dns.rdtypes.IN.A.A(IN, A, address = target)
            rdataset.add(rdata, ttl=300)
        elif rdataset.rdtype == CNAME:
            rdata = dns.rdtypes.ANY.CNAME.CNAME(IN, CNAME,
dns.name.Name((target,)))
            rdataset.add(rdata, ttl=300)
        else:
            assert False

        self._writeToZoneFile(host)


    def addZoneFile(self, file):
        """
        Function to create a new empty zone file, if none exists.  If
exists
        function will terminate.
        """
        newZoneSerial =  strftime("%Y%m%d00", localtime())
        zoneTemplate = Template('''$$TTL    ${ttltime}
    $$ORIGIN ${domain}.
    @       5M      IN      SOA     nsrepo1.foobar.priv.
dnsadmin.foobar.priv. (
                            ; did you update reverse?!
                            ${serial}  ; Serial CCYYMMDDxx where xx is
todays edit
                            1H
                            10M
                            1D
                            60M
    )''')

        if not os.path.exists(zoneDir + file + ".zone"):
            f = open(zoneDir + file + ".zone", "w")
            f.write(zoneTemplate.substitute({'ttltime':'300',
'domain': file, 'serial': newZoneSerial}))
            f.close()
        else:
            print "Zone: " + file + " already exists"



class RequestHandler(SimpleXMLRPCRequestHandler):
  #  rpc_paths = ('/RPC2',),
    pass

server = SimpleXMLRPCServer(("localhost", 8080), requestHandler =
RequestHandler, allow_none=True)

print "Listening on port 8080..."

server.register_introspection_functions()
server.register_instance(DNSFunctions())
server.register_multicall_functions()
server.serve_forever()


### Client Script ###
## I will probably use a mix of multicalls and singlecalls<?> for
client activity.  Muticalls will primarily be used for showing a
record, applying a change, then showing the same record again to
verify changes went through.

import xmlrpclib

proxy = xmlrpclib.ServerProxy('http://localhost:8080')
multicall = xmlrpclib.MultiCall(proxy)



print proxy.showRecord('host11.lab0.foobar.priv')
print proxy.showRecord('host12.lab0.foobar.priv')

multicall.showRecord('host11.lab0.foobar.priv')
multicall.changeRecord('host11.lab0.foorbar.priv', 'A', '127.0.0.1')
multicall.showRecord('host11.lab0.foobar.priv')

print proxy.system.listMethods
result = multicall()

print result[1], result[2]




More information about the Python-list mailing list