X-Git-Url: https://git.llucax.com/software/pymin.git/blobdiff_plain/031a757fb7b600a9015d018011cc7b135d7c8627..29b9cec06cf295e44693db06422ac986c9214ac4:/services/dns/__init__.py?ds=sidebyside diff --git a/services/dns/__init__.py b/services/dns/__init__.py index 6bc45e8..2ff6f60 100644 --- a/services/dns/__init__.py +++ b/services/dns/__init__.py @@ -1,40 +1,21 @@ # vim: set encoding=utf-8 et sw=4 sts=4 : # TODO COMMENT -from mako.template import Template -from mako.runtime import Context from os import path from os import unlink +from new import instancemethod -try: - import cPickle as pickle -except ImportError: - import pickle +from seqtools import Sequence +from dispatcher import handler, HandlerError, Handler +from services.util import Restorable, ConfigWriter, call +from services.util import InitdHandler, TransactionalHandler, ParametersHandler -try: - from seqtools import Sequence -except ImportError: - # NOP for testing - class Sequence: pass - -try: - from dispatcher import handler, HandlerError -except ImportError: - class HandlerError(RuntimeError): pass - def handler(f): return f # NOP for testing - - - -__ALL__ = ('DnsHandler',) - -pickle_ext = '.pkl' - -pickle_vars = 'vars' -pickle_zones = 'zones' - -config_filename = 'named.conf' -zone_filename = 'zoneX.zone' -zone_filename_ext = '.zone' +__ALL__ = ('DnsHandler', 'Error', + 'ZoneError', 'ZoneNotFoundError', 'ZoneAlreadyExistsError', + 'HostError', 'HostAlreadyExistsError', 'HostNotFoundError', + 'MailExchangeError', 'MailExchangeAlreadyExistsError', + 'MailExchangeNotFoundError', 'NameServerError', + 'NameServerAlreadyExistsError', 'NameServerNotFoundError') template_dir = path.join(path.dirname(__file__), 'templates') @@ -232,11 +213,11 @@ class Host(Sequence): def as_tuple(self): return (self.name, self.ip) -class HostHandler: +class HostHandler(Handler): def __init__(self,zones): self.zones = zones - @handler + @handler(u'Adds a host to a zone') def add(self, name, hostname, ip): if not name in self.zones: raise ZoneNotFoundError(name) @@ -245,7 +226,7 @@ class HostHandler: self.zones[name].hosts[hostname] = Host(hostname, ip) self.zones[name].mod = True - @handler + @handler(u'Updates a host ip in a zone') def update(self, name, hostname, ip): if not name in self.zones: raise ZoneNotFoundError(name) @@ -254,7 +235,7 @@ class HostHandler: self.zones[name].hosts[hostname].ip = ip self.zones[name].mod = True - @handler + @handler(u'Deletes a host from a zone') def delete(self, name, hostname): if not name in self.zones: raise ZoneNotFoundError(name) @@ -263,11 +244,11 @@ class HostHandler: del self.zones[name].hosts[hostname] self.zones[name].mod = True - @handler + @handler(u'Lists hosts') def list(self): return self.zones.keys() - @handler + @handler(u'Get insormation about all hosts') def show(self): return self.zones.values() @@ -281,12 +262,12 @@ class MailExchange(Sequence): def as_tuple(self): return (self.mx, self.prio) -class MailExchangeHandler: +class MailExchangeHandler(Handler): def __init__(self, zones): self.zones = zones - @handler + @handler(u'Adds a mail exchange to a zone') def add(self, zonename, mx, prio): if not zonename in self.zones: raise ZoneNotFoundError(zonename) @@ -295,7 +276,7 @@ class MailExchangeHandler: self.zones[zonename].mxs[mx] = MailExchange(mx, prio) self.zones[zonename].mod = True - @handler + @handler(u'Updates a mail exchange priority') def update(self, zonename, mx, prio): if not zonename in self.zones: raise ZoneNotFoundError(zonename) @@ -304,7 +285,7 @@ class MailExchangeHandler: self.zones[zonename].mxs[mx].prio = prio self.zones[zonename].mod = True - @handler + @handler(u'Deletes a mail exchange from a zone') def delete(self, zonename, mx): if not zonename in self.zones: raise ZoneNotFoundError(zonename) @@ -313,11 +294,11 @@ class MailExchangeHandler: del self.zones[zonename].mxs[mx] self.zones[zonename].mod = True - @handler + @handler(u'Lists mail exchangers') def list(self): return self.zones.keys() - @handler + @handler(u'Get information about all mail exchangers') def show(self): return self.zones.values() @@ -330,12 +311,12 @@ class NameServer(Sequence): def as_tuple(self): return (self.name) -class NameServerHandler: +class NameServerHandler(Handler): def __init__(self, zones): self.zones = zones - @handler + @handler(u'Adds a name server to a zone') def add(self, zone, ns): if not zone in self.zones: raise ZoneNotFoundError(zone) @@ -344,7 +325,7 @@ class NameServerHandler: self.zones[zone].nss[ns] = NameServer(ns) self.zones[zone].mod = True - @handler + @handler(u'Deletes a name server from a zone') def delete(self, zone, ns): if not zone in self.zones: raise ZoneNotFoundError(zone) @@ -353,11 +334,11 @@ class NameServerHandler: del self.zones[zone].nss[ns] self.zones[zone].mod = True - @handler + @handler(u'Lists name servers') def list(self): return self.zones.keys() - @handler + @handler(u'Get information about all name servers') def show(self): return self.zones.values() @@ -375,7 +356,7 @@ class Zone(Sequence): def as_tuple(self): return (self.name, self.hosts, self.mxs, self.nss) -class ZoneHandler: +class ZoneHandler(Handler): r"""ZoneHandler(zones) -> ZoneHandler instance :: Handle a list of zones. @@ -387,10 +368,10 @@ class ZoneHandler: def __init__(self, zones): self.zones = zones - @handler + @handler(u'Adds a zone') def add(self, name): if name in self.zones: - if self.zones[name].dele = True: + if self.zones[name].dele == True: self.zones[name].dele = False else: raise ZoneAlreadyExistsError(name) @@ -399,22 +380,23 @@ class ZoneHandler: self.zones[name].new = True - @handler + @handler(u'Deletes a zone') def delete(self, name): r"delete(name) -> None :: Delete a zone from the zone list." if not name in self.zones: raise ZoneNotFoundError(name) self.zones[name].dele = True - @handler + @handler(u'Lists zones') def list(self): return self.zones.keys() - @handler + @handler(u'Get information about all zones') def show(self): return self.zones.values() -class DnsHandler: +class DnsHandler(Restorable, ConfigWriter, InitdHandler, TransactionalHandler, + ParametersHandler): r"""DnsHandler([pickle_dir[, config_dir]]) -> DnsHandler instance. Handles DNS service commands for the dns program. @@ -426,151 +408,61 @@ class DnsHandler: Both defaults to the current working directory. """ - def __init__(self, pickle_dir='.', config_dir='.'): - r"Initialize DnsHandler object, see class documentation for details." - self.pickle_dir = pickle_dir - self.config_dir = config_dir - c_filename = path.join(template_dir, config_filename) - z_filename = path.join(template_dir, zone_filename) - self.config_template = Template(filename=c_filename) - self.zone_template = Template(filename=z_filename) - try : - self._load() - except IOError: - self.zones = dict() - self.vars = dict( + _initd_name = 'bind' + + _persistent_attrs = ('params', 'zones') + + _restorable_defaults = dict( + zones = dict(), + params = dict( isp_dns1 = '', isp_dns2 = '', bind_addr1 = '', bind_addr2 = '' - ) + ), + ) + + _config_writer_files = ('named.conf', 'zoneX.zone') + _config_writer_tpl_dir = path.join(path.dirname(__file__), 'templates') + def __init__(self, pickle_dir='.', config_dir='.'): + r"Initialize DnsHandler object, see class documentation for details." + self._persistent_dir = pickle_dir + self._config_writer_cfg_dir = config_dir + self.mod = False + self._config_build_templates() + self._restore() self.host = HostHandler(self.zones) self.zone = ZoneHandler(self.zones) self.mx = MailExchangeHandler(self.zones) self.ns = NameServerHandler(self.zones) - self.mod = False - @handler - def set(self, param, value): - r"set(param, value) -> None :: Set a DNS parameter." - if not param in self.vars: - raise ParameterNotFoundError(param) - self.vars[param] = value - self.mod = True - - @handler - def get(self, param): - r"get(param) -> None :: Get a DNS parameter." - if not param in self.vars: - raise ParameterNotFoundError(param) - return self.vars[param] - - @handler - def list(self): - return self.vars.keys() + def _zone_filename(self, zone): + return zone.name + '.zone' - @handler - def show(self): - return self.vars.values() - - @handler - def start(self): - r"start() -> None :: Start the DNS service." - #esto seria para poner en una interfaz - #y seria el hook para arrancar el servicio - pass - - @handler - def stop(self): - r"stop() -> None :: Stop the DNS service." - #esto seria para poner en una interfaz - #y seria el hook para arrancar el servicio - pass - - @handler - def restart(self): - r"restart() -> None :: Restart the DNS service." - #esto seria para poner en una interfaz - #y seria el hook para arrancar el servicio - pass - - @handler - def reload(self): - r"reload() -> None :: Reload the configuration of the DNS service." - #esto seria para poner en una interfaz - #y seria el hook para arrancar el servicio - pass - - @handler - def commit(self): - r"commit() -> None :: Commit the changes and reload the DNS service." - #esto seria para poner en una interfaz - #y seria que hace el pickle deberia llamarse - #al hacerse un commit - self._dump() - self._write_config() - self.reload() - - @handler - def rollback(self): - r"rollback() -> None :: Discard the changes not yet commited." - self._load() - - def _dump(self): - r"_dump() -> None :: Dump all persistent data to pickle files." - # XXX podría ir en una clase base - self._dump_var(self.vars, pickle_vars) - self._dump_var(self.zones, pickle_zones) - - def _load(self): - r"_load() -> None :: Load all persistent data from pickle files." - # XXX podría ir en una clase base - self.vars = self._load_var(pickle_vars) - self.zones = self._load_var(pickle_zones) - - def _pickle_filename(self, name): - r"_pickle_filename() -> string :: Construct a pickle filename." - # XXX podría ir en una clase base - return path.join(self.pickle_dir, name) + pickle_ext - - def _dump_var(self, var, name): - r"_dump_var() -> None :: Dump a especific variable to a pickle file." - # XXX podría ir en una clase base - pkl_file = file(self._pickle_filename(name), 'wb') - pickle.dump(var, pkl_file, 2) - pkl_file.close() - - def _load_var(self, name): - r"_load_var() -> object :: Load a especific pickle file." - # XXX podría ir en una clase base - return pickle.load(file(self._pickle_filename(name))) + def _get_config_vars(self, config_file): + return dict(zones=self.zones.values(), **self.params) def _write_config(self): r"_write_config() -> None :: Generate all the configuration files." - # XXX podría ir en una clase base, ver como generalizar variables a - # reemplazar en la template - #archivos de zona delete_zones = list() for a_zone in self.zones.values(): if a_zone.mod: if not a_zone.new: # TODO freeze de la zona - print 'Freezing zone ' + a_zone.name + zone_filename_ext - zone_out_file = file(path.join(self.config_dir, a_zone.name + zone_filename_ext), 'w') - ctx = Context( - zone_out_file, + call(('dns', 'freeze', a_zone.name)) + vars = dict( zone = a_zone, hosts = a_zone.hosts.values(), mxs = a_zone.mxs.values(), nss = a_zone.nss.values() - ) - self.zone_template.render_context(ctx) - zone_out_file.close() + ) + self._write_single_config('zoneX.zone', + self._zone_filename(a_zone), vars) a_zone.mod = False if not a_zone.new: # TODO unfreeze de la zona - print 'Unfreezing zone ' + a_zone.name + zone_filename_ext + call(('dns', 'unfreeze', a_zone.name)) else : self.mod = True a_zone.new = False @@ -578,7 +470,7 @@ class DnsHandler: #borro el archivo .zone try: self.mod = True - unlink(path.join(self.config_dir, a_zone.name + zone_filename_ext)) + unlink(self._zone_filename(a_zone)) except OSError: #la excepcion pude darse en caso que haga un add de una zona y #luego el del, como no hice commit, no se crea el archivo @@ -588,15 +480,10 @@ class DnsHandler: for z in delete_zones: del self.zones[z] #archivo general - if self.mod : - cfg_out_file = file(path.join(self.config_dir, config_filename), 'w') - ctx = Context(cfg_out_file, zones=self.zones.values(), **self.vars) - self.config_template.render_context(ctx) - cfg_out_file.close() + if self.mod: + self._write_single_config('named.conf') self.mod = False - print 'Restarting service' - - + self.reload() if __name__ == '__main__': @@ -638,26 +525,24 @@ if __name__ == '__main__': dns.commit() - print 'ZONAS :' - print dns.zone.show() + '\n' - print 'HOSTS :' - print dns.host.show() + print 'ZONAS :', dns.zone.show() + print 'HOSTS :', dns.host.show() #test zone errors - try: - dns.zone.update('zone-sarasa','lalal') - except ZoneNotFoundError, inst: - print 'Error: ', inst + #try: + # dns.zone.update('zone-sarasa','lalal') + #except ZoneNotFoundError, inst: + # print 'Error: ', inst try: dns.zone.delete('zone-sarasa') except ZoneNotFoundError, inst: print 'Error: ', inst - try: - dns.zone.add('zona_loca.com','ns1.dom.com','ns2.dom.com') - except ZoneAlreadyExistsError, inst: - print 'Error: ', inst + #try: + # dns.zone.add('zona_loca.com','ns1.dom.com','ns2.dom.com') + #except ZoneAlreadyExistsError, inst: + # print 'Error: ', inst #test hosts errors try: