]> git.llucax.com Git - software/pymin.git/commitdiff
Split plug-in code from handler code for services (refs #27).
authorLeandro Lucarella <llucax@gmail.com>
Mon, 16 Jun 2008 19:52:07 +0000 (16:52 -0300)
committerLeandro Lucarella <llucax@gmail.com>
Mon, 16 Jun 2008 19:52:07 +0000 (16:52 -0300)
20 files changed:
services/dhcp/__init__.py
services/dhcp/handler.py [new file with mode: 0644]
services/dns/__init__.py
services/dns/handler.py [new file with mode: 0644]
services/firewall/__init__.py
services/firewall/handler.py [new file with mode: 0644]
services/ip/__init__.py
services/ip/handler.py [new file with mode: 0644]
services/nat/__init__.py
services/nat/handler.py [new file with mode: 0644]
services/ppp/__init__.py
services/ppp/handler.py [new file with mode: 0644]
services/proxy/__init__.py
services/proxy/handler.py [new file with mode: 0644]
services/qos/__init__.py
services/qos/handler.py [new file with mode: 0644]
services/vpn/__init__.py
services/vpn/handler.py [new file with mode: 0644]
services/vrrp/__init__.py
services/vrrp/handler.py [new file with mode: 0644]

index c33a555ab31c4fcc989e67456b4f619efd0c0800..d493b1c53ba373d08d71934e9a6867d31df820dd 100644 (file)
@@ -1,145 +1,7 @@
 # vim: set encoding=utf-8 et sw=4 sts=4 :
 
-from os import path
-import logging ; log = logging.getLogger('pymin.services.dhcp')
-
-from pymin.seqtools import Sequence
-from pymin.dispatcher import Handler, handler, HandlerError
-from pymin.service.util import Restorable, ConfigWriter, InitdHandler, \
-                               TransactionalHandler, ParametersHandler, \
-                               DictSubHandler, ReloadHandler
-
-__all__ = ('DhcpHandler', 'get_service')
-
+from handler import DhcpHandler
 
 def get_service(config):
     return DhcpHandler(config.dhcp.pickle_dir, config.dhcp.config_dir)
 
-
-class Host(Sequence):
-    r"""Host(name, ip, mac) -> Host instance :: Class representing a host.
-
-    name - Host name, should be a fully qualified name, but no checks are done.
-    ip - IP assigned to the hostname.
-    mac - MAC address to associate to the hostname.
-    """
-
-    def __init__(self, name, ip, mac):
-        r"Initialize Host object, see class documentation for details."
-        self.name = name
-        self.ip = ip
-        self.mac = mac
-
-    def as_tuple(self):
-        r"Return a tuple representing the host."
-        return (self.name, self.ip, self.mac)
-
-    def update(self, ip=None, mac=None):
-        if ip is not None:
-            self.ip = ip
-        if mac is not None:
-            self.mac = mac
-
-class HostHandler(DictSubHandler):
-    r"""HostHandler(parent) -> HostHandler instance :: Handle a list of hosts.
-
-    This class is a helper for DhcpHandler to do all the work related to hosts
-    administration.
-    """
-
-    handler_help = u"Manage DHCP hosts"
-
-    _cont_subhandler_attr = 'hosts'
-    _cont_subhandler_class = Host
-
-class DhcpHandler(Restorable, ConfigWriter, ReloadHandler, TransactionalHandler,
-                  ParametersHandler, InitdHandler):
-    r"""DhcpHandler([pickle_dir[, config_dir]]) -> DhcpHandler instance.
-
-    Handles DHCP service commands for the dhcpd program.
-
-    pickle_dir - Directory where to write the persistent configuration data.
-
-    config_dir - Directory where to store de generated configuration files.
-
-    Both defaults to the current working directory.
-    """
-
-    handler_help = u"Manage DHCP service"
-
-    _initd_name = 'dhcpd'
-
-    _persistent_attrs = ('params', 'hosts')
-
-    _restorable_defaults = dict(
-            hosts = dict(),
-            params  = dict(
-                domain_name = 'example.com',
-                dns_1       = 'ns1.example.com',
-                dns_2       = 'ns2.example.com',
-                net_address = '192.168.0.0',
-                net_mask    = '255.255.255.0',
-                net_start   = '192.168.0.100',
-                net_end     = '192.168.0.200',
-                net_gateway = '192.168.0.1',
-            ),
-    )
-
-    _config_writer_files = 'dhcpd.conf'
-    _config_writer_tpl_dir = path.join(path.dirname(__file__), 'templates')
-
-    def __init__(self, pickle_dir='.', config_dir='.'):
-        r"Initialize DhcpHandler object, see class documentation for details."
-        log.debug(u'DhcpHandler(%r, %r)', pickle_dir, config_dir)
-        self._persistent_dir = pickle_dir
-        self._config_writer_cfg_dir = config_dir
-        self._config_build_templates()
-        InitdHandler.__init__(self)
-        self.host = HostHandler(self)
-
-    def _get_config_vars(self, config_file):
-        return dict(hosts=self.hosts.values(), **self.params)
-
-
-if __name__ == '__main__':
-
-    logging.basicConfig(
-        level   = logging.DEBUG,
-        format  = '%(asctime)s %(levelname)-8s %(message)s',
-        datefmt = '%H:%M:%S',
-    )
-
-    import os
-
-    h = DhcpHandler()
-
-    def dump():
-        print '-' * 80
-        print 'Variables:', h.list()
-        print h.show()
-        print
-        print 'Hosts:', h.host.list()
-        print h.host.show()
-        print '-' * 80
-
-    dump()
-
-    h.host.add('my_name','192.168.0.102','00:12:ff:56')
-
-    h.host.update('my_name','192.168.0.192','00:12:ff:56')
-
-    h.host.add('nico','192.168.0.188','00:00:00:00')
-
-    h.set('domain_name','baryon.com.ar')
-
-    try:
-        h.set('sarasa','baryon.com.ar')
-    except KeyError, e:
-        print 'Error:', e
-
-    h.commit()
-
-    dump()
-
-    os.system('rm -f *.pkl ' + ' '.join(h._config_writer_files))
-
diff --git a/services/dhcp/handler.py b/services/dhcp/handler.py
new file mode 100644 (file)
index 0000000..c33a555
--- /dev/null
@@ -0,0 +1,145 @@
+# vim: set encoding=utf-8 et sw=4 sts=4 :
+
+from os import path
+import logging ; log = logging.getLogger('pymin.services.dhcp')
+
+from pymin.seqtools import Sequence
+from pymin.dispatcher import Handler, handler, HandlerError
+from pymin.service.util import Restorable, ConfigWriter, InitdHandler, \
+                               TransactionalHandler, ParametersHandler, \
+                               DictSubHandler, ReloadHandler
+
+__all__ = ('DhcpHandler', 'get_service')
+
+
+def get_service(config):
+    return DhcpHandler(config.dhcp.pickle_dir, config.dhcp.config_dir)
+
+
+class Host(Sequence):
+    r"""Host(name, ip, mac) -> Host instance :: Class representing a host.
+
+    name - Host name, should be a fully qualified name, but no checks are done.
+    ip - IP assigned to the hostname.
+    mac - MAC address to associate to the hostname.
+    """
+
+    def __init__(self, name, ip, mac):
+        r"Initialize Host object, see class documentation for details."
+        self.name = name
+        self.ip = ip
+        self.mac = mac
+
+    def as_tuple(self):
+        r"Return a tuple representing the host."
+        return (self.name, self.ip, self.mac)
+
+    def update(self, ip=None, mac=None):
+        if ip is not None:
+            self.ip = ip
+        if mac is not None:
+            self.mac = mac
+
+class HostHandler(DictSubHandler):
+    r"""HostHandler(parent) -> HostHandler instance :: Handle a list of hosts.
+
+    This class is a helper for DhcpHandler to do all the work related to hosts
+    administration.
+    """
+
+    handler_help = u"Manage DHCP hosts"
+
+    _cont_subhandler_attr = 'hosts'
+    _cont_subhandler_class = Host
+
+class DhcpHandler(Restorable, ConfigWriter, ReloadHandler, TransactionalHandler,
+                  ParametersHandler, InitdHandler):
+    r"""DhcpHandler([pickle_dir[, config_dir]]) -> DhcpHandler instance.
+
+    Handles DHCP service commands for the dhcpd program.
+
+    pickle_dir - Directory where to write the persistent configuration data.
+
+    config_dir - Directory where to store de generated configuration files.
+
+    Both defaults to the current working directory.
+    """
+
+    handler_help = u"Manage DHCP service"
+
+    _initd_name = 'dhcpd'
+
+    _persistent_attrs = ('params', 'hosts')
+
+    _restorable_defaults = dict(
+            hosts = dict(),
+            params  = dict(
+                domain_name = 'example.com',
+                dns_1       = 'ns1.example.com',
+                dns_2       = 'ns2.example.com',
+                net_address = '192.168.0.0',
+                net_mask    = '255.255.255.0',
+                net_start   = '192.168.0.100',
+                net_end     = '192.168.0.200',
+                net_gateway = '192.168.0.1',
+            ),
+    )
+
+    _config_writer_files = 'dhcpd.conf'
+    _config_writer_tpl_dir = path.join(path.dirname(__file__), 'templates')
+
+    def __init__(self, pickle_dir='.', config_dir='.'):
+        r"Initialize DhcpHandler object, see class documentation for details."
+        log.debug(u'DhcpHandler(%r, %r)', pickle_dir, config_dir)
+        self._persistent_dir = pickle_dir
+        self._config_writer_cfg_dir = config_dir
+        self._config_build_templates()
+        InitdHandler.__init__(self)
+        self.host = HostHandler(self)
+
+    def _get_config_vars(self, config_file):
+        return dict(hosts=self.hosts.values(), **self.params)
+
+
+if __name__ == '__main__':
+
+    logging.basicConfig(
+        level   = logging.DEBUG,
+        format  = '%(asctime)s %(levelname)-8s %(message)s',
+        datefmt = '%H:%M:%S',
+    )
+
+    import os
+
+    h = DhcpHandler()
+
+    def dump():
+        print '-' * 80
+        print 'Variables:', h.list()
+        print h.show()
+        print
+        print 'Hosts:', h.host.list()
+        print h.host.show()
+        print '-' * 80
+
+    dump()
+
+    h.host.add('my_name','192.168.0.102','00:12:ff:56')
+
+    h.host.update('my_name','192.168.0.192','00:12:ff:56')
+
+    h.host.add('nico','192.168.0.188','00:00:00:00')
+
+    h.set('domain_name','baryon.com.ar')
+
+    try:
+        h.set('sarasa','baryon.com.ar')
+    except KeyError, e:
+        print 'Error:', e
+
+    h.commit()
+
+    dump()
+
+    os.system('rm -f *.pkl ' + ' '.join(h._config_writer_files))
+
index 23046c5645172df432c01975be70a75a59a2065c..1b5e4e59396b05bc11b7770000f1afd1dbf7e197 100644 (file)
@@ -1,295 +1,7 @@
 # vim: set encoding=utf-8 et sw=4 sts=4 :
 
-# TODO COMMENT
-from os import path
-from os import unlink
-import logging ; log = logging.getLogger('pymin.services.dns')
-
-from pymin.seqtools import Sequence
-from pymin.dispatcher import handler, HandlerError, Handler
-from pymin.service.util import Restorable, ConfigWriter, InitdHandler, \
-                               TransactionalHandler, ParametersHandler, \
-                               DictComposedSubHandler, DictSubHandler, call
-
-__all__ = ('DnsHandler', 'get_service')
-
+from handler import DnsHandler
 
 def get_service(config):
     return DnsHandler(config.dns.pickle_dir, config.dns.config_dir)
 
-
-class Host(Sequence):
-    def __init__(self, name, ip):
-        self.name = name
-        self.ip = ip
-    def update(self, ip=None):
-        if ip is not None: self.ip = ip
-    def as_tuple(self):
-        return (self.name, self.ip)
-
-class HostHandler(DictComposedSubHandler):
-    handler_help = u"Manage DNS hosts"
-    _comp_subhandler_cont = 'zones'
-    _comp_subhandler_attr = 'hosts'
-    _comp_subhandler_class = Host
-
-class MailExchange(Sequence):
-    def __init__(self, mx, prio):
-        self.mx = mx
-        self.prio = prio
-    def update(self, prio=None):
-        if prio is not None: self.prio = prio
-    def as_tuple(self):
-        return (self.mx, self.prio)
-
-class MailExchangeHandler(DictComposedSubHandler):
-    handler_help = u"Manage DNS mail exchangers (MX)"
-    _comp_subhandler_cont = 'zones'
-    _comp_subhandler_attr = 'mxs'
-    _comp_subhandler_class = MailExchange
-
-class NameServer(Sequence):
-    def __init__(self, name):
-        self.name = name
-    def as_tuple(self):
-        return (self.name,)
-
-class NameServerHandler(DictComposedSubHandler):
-    handler_help = u"Manage DNS name servers (NS)"
-    _comp_subhandler_cont = 'zones'
-    _comp_subhandler_attr = 'nss'
-    _comp_subhandler_class = NameServer
-
-class Zone(Sequence):
-    def __init__(self, name):
-        self.name = name
-        self.hosts = dict()
-        self.mxs = dict()
-        self.nss = dict()
-        self._add = False
-        self._update = False
-        self._delete = False
-    def as_tuple(self):
-        return (self.name, self.hosts, self.mxs, self.nss)
-
-class ZoneHandler(DictSubHandler):
-    handler_help = u"Manage DNS zones"
-    _cont_subhandler_attr = 'zones'
-    _cont_subhandler_class = Zone
-
-class DnsHandler(Restorable, ConfigWriter, InitdHandler, TransactionalHandler,
-                 ParametersHandler):
-    r"""DnsHandler([pickle_dir[, config_dir]]) -> DnsHandler instance.
-
-    Handles DNS service commands for the dns program.
-
-    pickle_dir - Directory where to write the persistent configuration data.
-
-    config_dir - Directory where to store de generated configuration files.
-
-    Both defaults to the current working directory.
-    """
-
-    handler_help = u"Manage DNS service"
-
-    _initd_name = 'named'
-
-    _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."
-        log.debug(u'DnsHandler(%r, %r)', pickle_dir, config_dir)
-        self._persistent_dir = pickle_dir
-        self._config_writer_cfg_dir = config_dir
-        self._update = False
-        self._config_build_templates()
-        InitdHandler.__init__(self)
-        self.host = HostHandler(self)
-        self.zone = ZoneHandler(self)
-        self.mx = MailExchangeHandler(self)
-        self.ns = NameServerHandler(self)
-
-    def _zone_filename(self, zone):
-        return zone.name + '.zone'
-
-    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."
-        log.debug(u'DnsHandler._write_config()')
-        delete_zones = list()
-        for a_zone in self.zones.values():
-            log.debug(u'DnsHandler._write_config: processing zone %s', a_zone)
-            if a_zone._update or a_zone._add:
-                if not a_zone._add and self._service_running:
-                    log.debug(u'DnsHandler._write_config: zone updated and '
-                                u'the service is running, freezing zone')
-                    call(('rndc', '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._write_single_config('zoneX.zone',
-                                            self._zone_filename(a_zone), vars)
-                a_zone._update = False
-                if not a_zone._add and self._service_running:
-                    log.debug(u'DnsHandler._write_config: unfreezing zone')
-                    call(('rndc', 'thaw', a_zone.name))
-                else :
-                    self._update = True
-                    a_zone._add = False
-            if a_zone._delete:
-                #borro el archivo .zone
-                log.debug(u'DnsHandler._write_config: zone deleted, removing '
-                            u'the file %r', self._zone_filename(a_zone))
-                try:
-                    self._update = True
-                    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
-                    log.debug(u'DnsHandler._write_config: file not found')
-                    pass
-                delete_zones.append(a_zone.name)
-        #borro las zonas
-        for z in delete_zones:
-            del self.zones[z]
-        #archivo general
-        if self._update:
-            self._write_single_config('named.conf')
-            self._update = False
-            return False # Do reload
-        return True # we don't need to reload
-
-    # HACK!!!!
-    def handle_timer(self):
-        log.debug(u'DnsHandler.handle_timer()')
-        import subprocess
-        p = subprocess.Popen(('pgrep', '-f', '/usr/sbin/named'),
-                                stdout=subprocess.PIPE)
-        pid = p.communicate()[0]
-        if p.returncode == 0 and len(pid) > 0:
-            log.debug(u'DnsHandler.handle_timer: pid present, running')
-            self._service_running = True
-        else:
-            log.debug(u'DnsHandler.handle_timer: pid absent, NOT running')
-            self._service_running = False
-
-
-
-if __name__ == '__main__':
-
-    logging.basicConfig(
-        level   = logging.DEBUG,
-        format  = '%(asctime)s %(levelname)-8s %(message)s',
-        datefmt = '%H:%M:%S',
-    )
-
-    dns = DnsHandler();
-
-    dns.set('isp_dns1','la_garcha.com')
-    dns.set('bind_addr1','localhost')
-    dns.zone.add('zona_loca.com')
-    #dns.zone.update('zona_loca.com','ns1.dominio.com')
-
-    dns.host.add('zona_loca.com','hostname_loco','192.168.0.23')
-    dns.host.update('zona_loca.com','hostname_loco','192.168.0.66')
-
-    dns.host.add('zona_loca.com','hostname_kuak','192.168.0.23')
-    dns.host.delete('zona_loca.com','hostname_kuak')
-
-    dns.host.add('zona_loca.com','hostname_kuang','192.168.0.24')
-    dns.host.add('zona_loca.com','hostname_chan','192.168.0.25')
-    dns.host.add('zona_loca.com','hostname_kaine','192.168.0.26')
-
-    dns.mx.add('zona_loca.com','mx1.sarasa.com',10)
-    dns.mx.update('zona_loca.com','mx1.sarasa.com',20)
-    dns.mx.add('zona_loca.com','mx2.sarasa.com',30)
-    dns.mx.add('zona_loca.com','mx3.sarasa.com',40)
-    dns.mx.delete('zona_loca.com','mx3.sarasa.com')
-
-    dns.ns.add('zona_loca.com','ns1.jua.com')
-    dns.ns.add('zona_loca.com','ns2.jua.com')
-    dns.ns.add('zona_loca.com','ns3.jua.com')
-    dns.ns.delete('zona_loca.com','ns3.jua.com')
-
-    dns.zone.add('zona_oscura')
-
-    dns.host.add('zona_oscura','hostname_a','192.168.0.24')
-    dns.host.add('zona_oscura','hostname_b','192.168.0.25')
-    dns.host.add('zona_oscura','hostname_c','192.168.0.26')
-
-    dns.zone.delete('zona_oscura')
-
-    dns.commit()
-
-    print 'ZONAS :', dns.zone.show()
-    for z in dns.zones:
-        print 'HOSTS from', z, ':', dns.host.show(z)
-
-    #test zone errors
-    #try:
-    #    dns.zone.update('zone-sarasa','lalal')
-    #except ZoneNotFoundError, inst:
-    #    print 'Error: ', inst
-
-    from pymin.services.util import ItemNotFoundError, ItemAlreadyExistsError, \
-                                    ContainerNotFoundError
-
-    try:
-        dns.zone.delete('zone-sarasa')
-    except ItemNotFoundError, 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:
-        dns.host.update('zone-sarasa','kuak','192.68')
-    except ContainerNotFoundError, inst:
-        print 'Error: ', inst
-
-    try:
-        dns.host.update('zona_loca.com','kuak','192.68')
-    except ItemNotFoundError, inst:
-        print 'Error: ', inst
-
-    try:
-        dns.host.delete('zone-sarasa','lala')
-    except ContainerNotFoundError, inst:
-        print 'Error: ', inst
-
-    try:
-        dns.host.delete('zona_loca.com','lala')
-    except ItemNotFoundError, inst:
-        print 'Error: ', inst
-
-    try:
-        dns.host.add('zona','hostname_loco','192.168.0.23')
-    except ContainerNotFoundError, inst:
-        print 'Error: ', inst
-
-    try:
-        dns.host.add('zona_loca.com','hostname_loco','192.168.0.23')
-    except ItemAlreadyExistsError, inst:
-        print 'Error: ', inst
diff --git a/services/dns/handler.py b/services/dns/handler.py
new file mode 100644 (file)
index 0000000..23046c5
--- /dev/null
@@ -0,0 +1,295 @@
+# vim: set encoding=utf-8 et sw=4 sts=4 :
+
+# TODO COMMENT
+from os import path
+from os import unlink
+import logging ; log = logging.getLogger('pymin.services.dns')
+
+from pymin.seqtools import Sequence
+from pymin.dispatcher import handler, HandlerError, Handler
+from pymin.service.util import Restorable, ConfigWriter, InitdHandler, \
+                               TransactionalHandler, ParametersHandler, \
+                               DictComposedSubHandler, DictSubHandler, call
+
+__all__ = ('DnsHandler', 'get_service')
+
+
+def get_service(config):
+    return DnsHandler(config.dns.pickle_dir, config.dns.config_dir)
+
+
+class Host(Sequence):
+    def __init__(self, name, ip):
+        self.name = name
+        self.ip = ip
+    def update(self, ip=None):
+        if ip is not None: self.ip = ip
+    def as_tuple(self):
+        return (self.name, self.ip)
+
+class HostHandler(DictComposedSubHandler):
+    handler_help = u"Manage DNS hosts"
+    _comp_subhandler_cont = 'zones'
+    _comp_subhandler_attr = 'hosts'
+    _comp_subhandler_class = Host
+
+class MailExchange(Sequence):
+    def __init__(self, mx, prio):
+        self.mx = mx
+        self.prio = prio
+    def update(self, prio=None):
+        if prio is not None: self.prio = prio
+    def as_tuple(self):
+        return (self.mx, self.prio)
+
+class MailExchangeHandler(DictComposedSubHandler):
+    handler_help = u"Manage DNS mail exchangers (MX)"
+    _comp_subhandler_cont = 'zones'
+    _comp_subhandler_attr = 'mxs'
+    _comp_subhandler_class = MailExchange
+
+class NameServer(Sequence):
+    def __init__(self, name):
+        self.name = name
+    def as_tuple(self):
+        return (self.name,)
+
+class NameServerHandler(DictComposedSubHandler):
+    handler_help = u"Manage DNS name servers (NS)"
+    _comp_subhandler_cont = 'zones'
+    _comp_subhandler_attr = 'nss'
+    _comp_subhandler_class = NameServer
+
+class Zone(Sequence):
+    def __init__(self, name):
+        self.name = name
+        self.hosts = dict()
+        self.mxs = dict()
+        self.nss = dict()
+        self._add = False
+        self._update = False
+        self._delete = False
+    def as_tuple(self):
+        return (self.name, self.hosts, self.mxs, self.nss)
+
+class ZoneHandler(DictSubHandler):
+    handler_help = u"Manage DNS zones"
+    _cont_subhandler_attr = 'zones'
+    _cont_subhandler_class = Zone
+
+class DnsHandler(Restorable, ConfigWriter, InitdHandler, TransactionalHandler,
+                 ParametersHandler):
+    r"""DnsHandler([pickle_dir[, config_dir]]) -> DnsHandler instance.
+
+    Handles DNS service commands for the dns program.
+
+    pickle_dir - Directory where to write the persistent configuration data.
+
+    config_dir - Directory where to store de generated configuration files.
+
+    Both defaults to the current working directory.
+    """
+
+    handler_help = u"Manage DNS service"
+
+    _initd_name = 'named'
+
+    _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."
+        log.debug(u'DnsHandler(%r, %r)', pickle_dir, config_dir)
+        self._persistent_dir = pickle_dir
+        self._config_writer_cfg_dir = config_dir
+        self._update = False
+        self._config_build_templates()
+        InitdHandler.__init__(self)
+        self.host = HostHandler(self)
+        self.zone = ZoneHandler(self)
+        self.mx = MailExchangeHandler(self)
+        self.ns = NameServerHandler(self)
+
+    def _zone_filename(self, zone):
+        return zone.name + '.zone'
+
+    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."
+        log.debug(u'DnsHandler._write_config()')
+        delete_zones = list()
+        for a_zone in self.zones.values():
+            log.debug(u'DnsHandler._write_config: processing zone %s', a_zone)
+            if a_zone._update or a_zone._add:
+                if not a_zone._add and self._service_running:
+                    log.debug(u'DnsHandler._write_config: zone updated and '
+                                u'the service is running, freezing zone')
+                    call(('rndc', '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._write_single_config('zoneX.zone',
+                                            self._zone_filename(a_zone), vars)
+                a_zone._update = False
+                if not a_zone._add and self._service_running:
+                    log.debug(u'DnsHandler._write_config: unfreezing zone')
+                    call(('rndc', 'thaw', a_zone.name))
+                else :
+                    self._update = True
+                    a_zone._add = False
+            if a_zone._delete:
+                #borro el archivo .zone
+                log.debug(u'DnsHandler._write_config: zone deleted, removing '
+                            u'the file %r', self._zone_filename(a_zone))
+                try:
+                    self._update = True
+                    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
+                    log.debug(u'DnsHandler._write_config: file not found')
+                    pass
+                delete_zones.append(a_zone.name)
+        #borro las zonas
+        for z in delete_zones:
+            del self.zones[z]
+        #archivo general
+        if self._update:
+            self._write_single_config('named.conf')
+            self._update = False
+            return False # Do reload
+        return True # we don't need to reload
+
+    # HACK!!!!
+    def handle_timer(self):
+        log.debug(u'DnsHandler.handle_timer()')
+        import subprocess
+        p = subprocess.Popen(('pgrep', '-f', '/usr/sbin/named'),
+                                stdout=subprocess.PIPE)
+        pid = p.communicate()[0]
+        if p.returncode == 0 and len(pid) > 0:
+            log.debug(u'DnsHandler.handle_timer: pid present, running')
+            self._service_running = True
+        else:
+            log.debug(u'DnsHandler.handle_timer: pid absent, NOT running')
+            self._service_running = False
+
+
+
+if __name__ == '__main__':
+
+    logging.basicConfig(
+        level   = logging.DEBUG,
+        format  = '%(asctime)s %(levelname)-8s %(message)s',
+        datefmt = '%H:%M:%S',
+    )
+
+    dns = DnsHandler();
+
+    dns.set('isp_dns1','la_garcha.com')
+    dns.set('bind_addr1','localhost')
+    dns.zone.add('zona_loca.com')
+    #dns.zone.update('zona_loca.com','ns1.dominio.com')
+
+    dns.host.add('zona_loca.com','hostname_loco','192.168.0.23')
+    dns.host.update('zona_loca.com','hostname_loco','192.168.0.66')
+
+    dns.host.add('zona_loca.com','hostname_kuak','192.168.0.23')
+    dns.host.delete('zona_loca.com','hostname_kuak')
+
+    dns.host.add('zona_loca.com','hostname_kuang','192.168.0.24')
+    dns.host.add('zona_loca.com','hostname_chan','192.168.0.25')
+    dns.host.add('zona_loca.com','hostname_kaine','192.168.0.26')
+
+    dns.mx.add('zona_loca.com','mx1.sarasa.com',10)
+    dns.mx.update('zona_loca.com','mx1.sarasa.com',20)
+    dns.mx.add('zona_loca.com','mx2.sarasa.com',30)
+    dns.mx.add('zona_loca.com','mx3.sarasa.com',40)
+    dns.mx.delete('zona_loca.com','mx3.sarasa.com')
+
+    dns.ns.add('zona_loca.com','ns1.jua.com')
+    dns.ns.add('zona_loca.com','ns2.jua.com')
+    dns.ns.add('zona_loca.com','ns3.jua.com')
+    dns.ns.delete('zona_loca.com','ns3.jua.com')
+
+    dns.zone.add('zona_oscura')
+
+    dns.host.add('zona_oscura','hostname_a','192.168.0.24')
+    dns.host.add('zona_oscura','hostname_b','192.168.0.25')
+    dns.host.add('zona_oscura','hostname_c','192.168.0.26')
+
+    dns.zone.delete('zona_oscura')
+
+    dns.commit()
+
+    print 'ZONAS :', dns.zone.show()
+    for z in dns.zones:
+        print 'HOSTS from', z, ':', dns.host.show(z)
+
+    #test zone errors
+    #try:
+    #    dns.zone.update('zone-sarasa','lalal')
+    #except ZoneNotFoundError, inst:
+    #    print 'Error: ', inst
+
+    from pymin.services.util import ItemNotFoundError, ItemAlreadyExistsError, \
+                                    ContainerNotFoundError
+
+    try:
+        dns.zone.delete('zone-sarasa')
+    except ItemNotFoundError, 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:
+        dns.host.update('zone-sarasa','kuak','192.68')
+    except ContainerNotFoundError, inst:
+        print 'Error: ', inst
+
+    try:
+        dns.host.update('zona_loca.com','kuak','192.68')
+    except ItemNotFoundError, inst:
+        print 'Error: ', inst
+
+    try:
+        dns.host.delete('zone-sarasa','lala')
+    except ContainerNotFoundError, inst:
+        print 'Error: ', inst
+
+    try:
+        dns.host.delete('zona_loca.com','lala')
+    except ItemNotFoundError, inst:
+        print 'Error: ', inst
+
+    try:
+        dns.host.add('zona','hostname_loco','192.168.0.23')
+    except ContainerNotFoundError, inst:
+        print 'Error: ', inst
+
+    try:
+        dns.host.add('zona_loca.com','hostname_loco','192.168.0.23')
+    except ItemAlreadyExistsError, inst:
+        print 'Error: ', inst
index 50a8dfb10683a2418b317186d05373faa7932d1a..2c8e091124646f381685ea936e78e73841463dd8 100644 (file)
@@ -1,145 +1,7 @@
 # vim: set encoding=utf-8 et sw=4 sts=4 :
 
-# TODO See if it's better (more secure) to execute commands via python instead
-# of using script templates.
-
-from os import path
-from formencode import Invalid
-from formencode.validators import OneOf, CIDR, Int
-import logging ; log = logging.getLogger('pymin.services.firewall')
-
-from pymin.item import Item
-from pymin.validatedclass import Field
-from pymin.dispatcher import Handler, handler, HandlerError
-from pymin.service.util import Restorable, ConfigWriter, ServiceHandler, \
-                               TransactionalHandler, ListSubHandler
-
-__all__ = ('FirewallHandler', 'get_service')
-
+from handler import FirewallHandler
 
 def get_service(config):
     return FirewallHandler(config.firewall.pickle_dir, config.firewall.config_dir)
 
-
-class UpOneOf(OneOf):
-    def validate_python(self, value, state):
-        value = value.upper()
-        return OneOf.validate_python(self, value, state)
-
-class Rule(Item):
-    r"""Rule(chain, target[, src[, dst[, ...]]]) -> Rule instance.
-
-    chain - INPUT, OUTPUT or FORWARD.
-    target - ACCEPT, REJECT or DROP.
-    src - Source subnet as IP/mask.
-    dst - Destination subnet as IP/mask.
-    protocol - ICMP, UDP, TCP or ALL.
-    src_port - Source port (only for UDP or TCP protocols).
-    dst_port - Destination port (only for UDP or TCP protocols).
-    """
-    chain = Field(UpOneOf(['INPUT', 'OUTPUT', 'FORWARD'], not_empty=True))
-    target = Field(UpOneOf(['ACCEPT', 'REJECT', 'DROP'], not_empty=True))
-    src = Field(CIDR(if_empty=None, if_missing=None))
-    dst = Field(CIDR(if_empty=None, if_missing=None))
-    protocol = Field(UpOneOf(['ICMP', 'UDP', 'TCP', 'ALL'], if_missing=None))
-    src_port = Field(Int(min=0, max=65535, if_empty=None, if_missing=None))
-    dst_port = Field(Int(min=0, max=65535, if_empty=None, if_missing=None))
-    def chained_validator(self, fields, state):
-        errors = dict()
-        if fields['protocol'] not in ('TCP', 'UDP'):
-            for name in ('src_port', 'dst_port'):
-                if fields[name] is not None:
-                    errors[name] = u"Should be None if protocol " \
-                            "(%(protocol)s) is not TCP or UDP" % fields
-        if errors:
-            raise Invalid(u"You can't specify any ports if the protocol "
-                        u'is not TCP or UDP', fields, state, error_dict=errors)
-
-class RuleHandler(ListSubHandler):
-    r"""RuleHandler(parent) -> RuleHandler instance :: Handle a list of rules.
-
-    This class is a helper for FirewallHandler to do all the work related to rules
-    administration.
-
-    parent - The parent service handler.
-    """
-
-    handler_help = u"Manage firewall rules"
-
-    _cont_subhandler_attr = 'rules'
-    _cont_subhandler_class = Rule
-
-class FirewallHandler(Restorable, ConfigWriter, ServiceHandler,
-                      TransactionalHandler):
-    r"""FirewallHandler([pickle_dir[, config_dir]]) -> FirewallHandler instance.
-
-    Handles firewall commands using iptables.
-
-    pickle_dir - Directory where to write the persistent configuration data.
-
-    config_dir - Directory where to store de generated configuration files.
-
-    Both defaults to the current working directory.
-    """
-
-    handler_help = u"Manage firewall service"
-
-    _persistent_attrs = ['rules']
-
-    _restorable_defaults = dict(rules=list())
-
-    _config_writer_files = 'iptables.sh'
-    _config_writer_tpl_dir = path.join(path.dirname(__file__), 'templates')
-
-    def __init__(self, pickle_dir='.', config_dir='.'):
-        r"Initialize the object, see class documentation for details."
-        log.debug(u'FirewallHandler(%r, %r)', pickle_dir, config_dir)
-        self._persistent_dir = pickle_dir
-        self._config_writer_cfg_dir = config_dir
-        self._service_start = ('sh', path.join(self._config_writer_cfg_dir,
-                                        self._config_writer_files))
-        self._service_stop = ('iptables', '-t', 'filter', '-F')
-        self._service_restart = self._service_start
-        self._service_reload = self._service_start
-        self._config_build_templates()
-        ServiceHandler.__init__(self)
-        self.rule = RuleHandler(self)
-
-    def _get_config_vars(self, config_file):
-        return dict(rules=self.rules)
-
-
-if __name__ == '__main__':
-
-    logging.basicConfig(
-        level   = logging.DEBUG,
-        format  = '%(asctime)s %(levelname)-8s %(message)s',
-        datefmt = '%H:%M:%S',
-    )
-
-    import os
-
-    fw_handler = FirewallHandler()
-
-    def dump():
-        print '-' * 80
-        print 'Rules:'
-        print fw_handler.rule.show()
-        print '-' * 80
-
-    dump()
-
-    fw_handler.rule.add('input', 'drop', protocol='icmp')
-
-    fw_handler.rule.update(0, dst='192.168.0.188/32')
-
-    fw_handler.rule.add('output', 'accept', '192.168.1.0/24')
-
-    fw_handler.commit()
-
-    fw_handler.stop()
-
-    dump()
-
-    os.system('rm -f *.pkl iptables.sh')
-
diff --git a/services/firewall/handler.py b/services/firewall/handler.py
new file mode 100644 (file)
index 0000000..50a8dfb
--- /dev/null
@@ -0,0 +1,145 @@
+# vim: set encoding=utf-8 et sw=4 sts=4 :
+
+# TODO See if it's better (more secure) to execute commands via python instead
+# of using script templates.
+
+from os import path
+from formencode import Invalid
+from formencode.validators import OneOf, CIDR, Int
+import logging ; log = logging.getLogger('pymin.services.firewall')
+
+from pymin.item import Item
+from pymin.validatedclass import Field
+from pymin.dispatcher import Handler, handler, HandlerError
+from pymin.service.util import Restorable, ConfigWriter, ServiceHandler, \
+                               TransactionalHandler, ListSubHandler
+
+__all__ = ('FirewallHandler', 'get_service')
+
+
+def get_service(config):
+    return FirewallHandler(config.firewall.pickle_dir, config.firewall.config_dir)
+
+
+class UpOneOf(OneOf):
+    def validate_python(self, value, state):
+        value = value.upper()
+        return OneOf.validate_python(self, value, state)
+
+class Rule(Item):
+    r"""Rule(chain, target[, src[, dst[, ...]]]) -> Rule instance.
+
+    chain - INPUT, OUTPUT or FORWARD.
+    target - ACCEPT, REJECT or DROP.
+    src - Source subnet as IP/mask.
+    dst - Destination subnet as IP/mask.
+    protocol - ICMP, UDP, TCP or ALL.
+    src_port - Source port (only for UDP or TCP protocols).
+    dst_port - Destination port (only for UDP or TCP protocols).
+    """
+    chain = Field(UpOneOf(['INPUT', 'OUTPUT', 'FORWARD'], not_empty=True))
+    target = Field(UpOneOf(['ACCEPT', 'REJECT', 'DROP'], not_empty=True))
+    src = Field(CIDR(if_empty=None, if_missing=None))
+    dst = Field(CIDR(if_empty=None, if_missing=None))
+    protocol = Field(UpOneOf(['ICMP', 'UDP', 'TCP', 'ALL'], if_missing=None))
+    src_port = Field(Int(min=0, max=65535, if_empty=None, if_missing=None))
+    dst_port = Field(Int(min=0, max=65535, if_empty=None, if_missing=None))
+    def chained_validator(self, fields, state):
+        errors = dict()
+        if fields['protocol'] not in ('TCP', 'UDP'):
+            for name in ('src_port', 'dst_port'):
+                if fields[name] is not None:
+                    errors[name] = u"Should be None if protocol " \
+                            "(%(protocol)s) is not TCP or UDP" % fields
+        if errors:
+            raise Invalid(u"You can't specify any ports if the protocol "
+                        u'is not TCP or UDP', fields, state, error_dict=errors)
+
+class RuleHandler(ListSubHandler):
+    r"""RuleHandler(parent) -> RuleHandler instance :: Handle a list of rules.
+
+    This class is a helper for FirewallHandler to do all the work related to rules
+    administration.
+
+    parent - The parent service handler.
+    """
+
+    handler_help = u"Manage firewall rules"
+
+    _cont_subhandler_attr = 'rules'
+    _cont_subhandler_class = Rule
+
+class FirewallHandler(Restorable, ConfigWriter, ServiceHandler,
+                      TransactionalHandler):
+    r"""FirewallHandler([pickle_dir[, config_dir]]) -> FirewallHandler instance.
+
+    Handles firewall commands using iptables.
+
+    pickle_dir - Directory where to write the persistent configuration data.
+
+    config_dir - Directory where to store de generated configuration files.
+
+    Both defaults to the current working directory.
+    """
+
+    handler_help = u"Manage firewall service"
+
+    _persistent_attrs = ['rules']
+
+    _restorable_defaults = dict(rules=list())
+
+    _config_writer_files = 'iptables.sh'
+    _config_writer_tpl_dir = path.join(path.dirname(__file__), 'templates')
+
+    def __init__(self, pickle_dir='.', config_dir='.'):
+        r"Initialize the object, see class documentation for details."
+        log.debug(u'FirewallHandler(%r, %r)', pickle_dir, config_dir)
+        self._persistent_dir = pickle_dir
+        self._config_writer_cfg_dir = config_dir
+        self._service_start = ('sh', path.join(self._config_writer_cfg_dir,
+                                        self._config_writer_files))
+        self._service_stop = ('iptables', '-t', 'filter', '-F')
+        self._service_restart = self._service_start
+        self._service_reload = self._service_start
+        self._config_build_templates()
+        ServiceHandler.__init__(self)
+        self.rule = RuleHandler(self)
+
+    def _get_config_vars(self, config_file):
+        return dict(rules=self.rules)
+
+
+if __name__ == '__main__':
+
+    logging.basicConfig(
+        level   = logging.DEBUG,
+        format  = '%(asctime)s %(levelname)-8s %(message)s',
+        datefmt = '%H:%M:%S',
+    )
+
+    import os
+
+    fw_handler = FirewallHandler()
+
+    def dump():
+        print '-' * 80
+        print 'Rules:'
+        print fw_handler.rule.show()
+        print '-' * 80
+
+    dump()
+
+    fw_handler.rule.add('input', 'drop', protocol='icmp')
+
+    fw_handler.rule.update(0, dst='192.168.0.188/32')
+
+    fw_handler.rule.add('output', 'accept', '192.168.1.0/24')
+
+    fw_handler.commit()
+
+    fw_handler.stop()
+
+    dump()
+
+    os.system('rm -f *.pkl iptables.sh')
+
index 2bbc288cf665cbef39859b056a2af9c7cbdae9f6..8840e224c747af768bb6c15b44686a6552de47a3 100644 (file)
@@ -1,376 +1,7 @@
 # vim: set encoding=utf-8 et sw=4 sts=4 :
 
-from subprocess import Popen, PIPE
-from os import path
-import logging ; log = logging.getLogger('pymin.services.ip')
-
-from pymin.seqtools import Sequence
-from pymin.dispatcher import handler, HandlerError, Handler
-from pymin.service.util import Restorable, ConfigWriter, InitdHandler, \
-                               TransactionalHandler, SubHandler, call, \
-                               get_network_devices, ListComposedSubHandler, \
-                               DictComposedSubHandler, ListSubHandler, \
-                               Device, Address, ExecutionError
-
-__all__ = ('IpHandler', 'get_service')
-
+from handler import IpHandler
 
 def get_service(config):
     return IpHandler(config.ip.pickle_dir, config.ip.config_dir)
 
-
-class Hop(Sequence):
-
-    def __init__(self, gateway, device):
-        self.gateway = gateway
-        self.device = device
-
-    def as_tuple(self):
-        return (self.gateway, self.device)
-
-    def __cmp__(self, other):
-        if self.gateway == other.gateway \
-                and self.device == other.device:
-            return 0
-        return cmp(id(self), id(other))
-
-class HopHandler(ListSubHandler):
-    handler_help = u"Manage IP hops"
-    _cont_subhandler_attr = 'hops'
-    _cont_subhandler_class = Hop
-
-    @handler('Add a hop: add <device> <gateway>')
-    def add(self, dev, gw):
-        if not dev in self.parent.devices:
-            raise DeviceNotFoundError(device)
-        return ListSubHandler.add(self, dev, gw)
-
-
-class Route(Sequence):
-    def __init__(self, net_addr, prefix, gateway):
-        self.net_addr = net_addr
-        self.prefix = prefix
-        self.gateway = gateway
-
-    def update(self, net_addr=None, prefix=None, gateway=None):
-        if net_addr is not None: self.net_addr = net_addr
-        if prefix is not None: self.prefix = prefix
-        if gateway is not None: self.gateway = gateway
-
-    def as_tuple(self):
-        return(self.net_addr, self.prefix, self.gateway)
-
-    def __cmp__(self, other):
-        if self.net_addr == other.net_addr \
-                and self.prefix == other.prefix \
-                and self.gateway == other.gateway:
-            return 0
-        return cmp(id(self), id(other))
-
-class RouteHandler(ListComposedSubHandler):
-    handler_help = u"Manage IP routes"
-    _comp_subhandler_cont = 'devices'
-    _comp_subhandler_attr = 'routes'
-    _comp_subhandler_class = Route
-
-    @handler(u'Adds a route to : ip route add <net_addr> <prefix> <gateway> [device]')
-    def add(self, net_addr, prefix, gateway, dev=None):
-        if dev is not None:
-            ListComposedSubHandler.add(self, dev, net_addr, prefix, gateway)
-        else:
-            r = Route(net_addr, prefix, gateway)
-            if not r in self.parent.no_device_routes:
-                self.parent.no_device_routes.append(r)
-
-    @handler("Deletes a route : ip route delete <route_number_in_show> [dev]")
-    def delete(self, index, dev=None):
-        if dev is not None:
-            ListComposedSubHandler.delete(self, dev, index)
-        else:
-            i = int(index)
-            del self.parent.no_device_routes[i]
-
-    @handler("Shows routes : ip route show [dev]")
-    def show(self, dev=None):
-        if dev is not None:
-            return ListComposedSubHandler.show(self, dev)
-        else:
-            return self.parent.no_device_routes
-
-class AddressHandler(DictComposedSubHandler):
-    handler_help = u"Manage IP addresses"
-    _comp_subhandler_cont = 'devices'
-    _comp_subhandler_attr = 'addrs'
-    _comp_subhandler_class = Address
-
-
-class DeviceHandler(SubHandler):
-
-    handler_help = u"Manage network devices"
-
-    def __init__(self, parent):
-        log.debug(u'DeviceHandler(%r)', parent)
-        # FIXME remove templates to execute commands
-        from mako.template import Template
-        self.parent = parent
-        template_dir = path.join(path.dirname(__file__), 'templates')
-        dev_fn = path.join(template_dir, 'device')
-        self.device_template = Template(filename=dev_fn)
-
-    @handler(u'Bring the device up')
-    def up(self, name):
-        log.debug(u'DeviceHandler.up(%r)', name)
-        if name in self.parent.devices:
-            call(self.device_template.render(dev=name, action='up'), shell=True)
-            #bring up all the route asocitaed to the device
-            for route in self.parent.devices[name].routes:
-                try:
-                    log.debug(u'IpHandler.up: adding %r', route)
-                    call(self.parent._render_config('route_add', dict(
-                            dev = name,
-                            net_addr = route.net_addr,
-                            prefix = route.prefix,
-                            gateway = route.gateway,
-                        )
-                    ), shell=True)
-                except ExecutionError, e:
-                    log.debug(u'IpHandler.up: error adding %r -> %r', route, e)
-            self.parent._bring_up_no_dev_routes()
-            self.parent._restart_services()
-        else:
-            log.debug(u'DeviceHandler.up: device not found')
-            raise DeviceNotFoundError(name)
-
-    @handler(u'Bring the device down')
-    def down(self, name):
-        log.debug(u'DeviceHandler.down(%r)', name)
-        if name in self.parent.devices:
-            call(self.device_template.render(dev=name, action='down'), shell=True)
-            self.parent._bring_up_no_dev_routes()
-            self.parent._restart_services()
-        else:
-            log.debug(u'DeviceHandler.up: device not found')
-            raise DeviceNotFoundError(name)
-
-    @handler(u'List all devices')
-    def list(self):
-        log.debug(u'DeviceHandler.list()')
-        return self.parent.devices.keys()
-
-    @handler(u'Get information about a device')
-    def show(self):
-        log.debug(u'DeviceHandler.show()')
-        return self.parent.devices.items()
-
-class IpHandler(Restorable, ConfigWriter, TransactionalHandler):
-
-    handler_help = u"Manage IP devices, addresses, routes and hops"
-
-    _persistent_attrs = ('devices','hops','no_device_routes')
-
-    _restorable_defaults = dict(
-                            devices=get_network_devices(),
-                            hops = list(),
-                            no_device_routes = list(),
-                            )
-
-    _config_writer_files = ('device', 'ip_add', 'ip_del', 'ip_flush',
-                            'route_add', 'route_del', 'route_flush', 'hop')
-    _config_writer_tpl_dir = path.join(path.dirname(__file__), 'templates')
-
-    def __init__(self, pickle_dir='.', config_dir='.'):
-        r"Initialize DhcpHandler object, see class documentation for details."
-        log.debug(u'IpHandler(%r, %r)', pickle_dir, config_dir)
-        self._persistent_dir = pickle_dir
-        self._config_writer_cfg_dir = config_dir
-        self._config_build_templates()
-        self._restore()
-        self._write_config()
-        self.addr = AddressHandler(self)
-        self.route = RouteHandler(self)
-        self.dev = DeviceHandler(self)
-        self.hop = HopHandler(self)
-        self.no_device_routes = list()
-        self.services = list()
-
-    def _write_config(self):
-        r"_write_config() -> None :: Execute all commands."
-        log.debug(u'IpHandler._write_config()')
-        for device in self.devices.values():
-            log.debug(u'IpHandler._write_config: processing device %s', device)
-            if device.active:
-                self._write_config_for_device(device)
-        self._bring_up_no_dev_routes()
-        self._write_hops()
-
-    def _bring_up_no_dev_routes(self):
-        log.debug(u'IpHandler._bring_up_no_dev_routes()')
-        for route in self.no_device_routes:
-            try:
-                log.debug(u'IpHandler._bring_up_no_dev_routes: add %r', route)
-                call(self._render_config('route_add', dict(
-                        dev = None,
-                        net_addr = route.net_addr,
-                        prefix = route.prefix,
-                        gateway = route.gateway,
-                    )
-                ), shell=True)
-            except ExecutionError, e:
-                log.debug(u'IpHandler._write_config: error flushing -> %r', e)
-
-    def _write_hops(self):
-        r"_write_hops() -> None :: Execute all hops."
-        log.debug(u'IpHandler._write_hops()')
-        if self.hops:
-            log.debug(u'IpHandler._write_hops: we have hops: %r', self.hops)
-            try:
-                log.debug(u'IpHandler._write_hops: flushing default hops')
-                call('ip route del default', shell=True)
-            except ExecutionError, e:
-                log.debug(u'IpHandler._write_hops: error adding -> %r', e)
-            try:
-                log.debug(u'IpHandler._write_hops: configuring hops')
-                #get hops for active devices
-                active_hops = dict()
-                for h in self.hops:
-                    if h.device in self.devices:
-                        if self.devices[h.device].active:
-                            active_hops.append(h)
-                call(self._render_config('hop', dict(
-                    hops = active_hops,
-                        )
-                ), shell=True)
-            except ExecutionError, e:
-                log.debug(u'IpHandler._write_hops: error adding -> %r', e)
-
-    def _write_config_for_device(self, device):
-        r"_write_config_for_device(self, device) -> None :: Execute commands."
-        log.debug(u'IpHandler._write_config_for_device()')
-        try:
-            log.debug(u'IpHandler._write_config_for_device: flushing routes...')
-            call(self._render_config('route_flush', dict(dev=device.name)),
-                        shell=True)
-        except ExecutionError, e:
-            log.debug(u'IpHandler._write_config_for_device: error flushing '
-                        u'-> %r', e)
-        try:
-            log.debug(u'IpHandler._write_config_for_device: flushing addrs...')
-            call(self._render_config('ip_flush', dict(dev=device.name)),
-                        shell=True)
-        except ExecutionError, e:
-            log.debug(u'IpHandler._write_config_for_device: error flushing '
-                        u'-> %r', e)
-        for address in device.addrs.values():
-            broadcast = address.broadcast
-            if broadcast is None:
-                broadcast = '+'
-            try:
-                log.debug(u'IpHandler._write_config_for_device: adding %r',
-                            address)
-                call(self._render_config('ip_add', dict(
-                    dev = device.name,
-                    addr = address.ip,
-                    netmask = address.netmask,
-                    peer = address.peer,
-                    broadcast = broadcast,
-                    )
-                ), shell=True)
-            except ExecutionError, e:
-                log.debug(u'IpHandler._write_config_for_device: error adding '
-                            u'-> %r', e)
-        for route in device.routes:
-            try:
-                log.debug(u'IpHandler._write_config_for_device: adding %r',
-                            route)
-                call(self._render_config('route_add', dict(
-                        dev = device.name,
-                        net_addr = route.net_addr,
-                        prefix = route.prefix,
-                        gateway = route.gateway,
-                    )
-                ), shell=True)
-            except ExecutionError, e:
-                log.debug(u'IpHandler._write_config_for_device: error adding '
-                            u'-> %r', e)
-
-    def handle_timer(self):
-        log.debug(u'IpHandler.handle_timer()')
-        self.refresh_devices()
-
-    def refresh_devices(self):
-        log.debug(u'IpHandler.update_devices()')
-        devices = get_network_devices()
-        #add not registered and active devices
-        go_active = False
-        for k,v in devices.items():
-            if k not in self.devices:
-                log.debug(u'IpHandler.update_devices: adding %r', v)
-                self.devices[k] = v
-            elif not self.devices[k].active:
-                self.active = True
-                go_active = True
-                self._write_config_for_device(self.devices[k])
-        if go_active:
-            self._write_hops()
-            self._bring_up_no_dev_routes()
-            self._restart_services()
-
-        #mark inactive devices
-        for k in self.devices.keys():
-            go_down = False
-            if k not in devices:
-                log.debug(u'IpHandler.update_devices: removing %s', k)
-                self.devices[k].active = False
-                go_down = True
-            if go_down:
-                self._bring_up_no_dev_routes()
-
-    def _restart_services(self):
-        for s in self.services:
-            if s._service_running:
-                try:
-                     s.stop()
-                except ExecutionError:
-                    pass
-                try:
-                    s.start()
-                except ExecutionError:
-                    pass
-
-       #hooks a service to the ip handler, so when
-       #a device is brought up one can restart the service
-       #that need to refresh their device list
-    def device_up_hook(self, serv):
-        if hasattr(serv, 'stop') and hasattr(serv, 'start'):
-            self.services.append(serv)
-
-
-
-
-
-if __name__ == '__main__':
-
-    logging.basicConfig(
-        level   = logging.DEBUG,
-        format  = '%(asctime)s %(levelname)-8s %(message)s',
-        datefmt = '%H:%M:%S',
-    )
-
-    ip = IpHandler()
-    print '----------------------'
-    ip.hop.add('201.21.32.53','eth0')
-    ip.hop.add('205.65.65.25','eth1')
-    ip.commit()
-    ip.dev.up('eth0')
-    ip.addr.add('eth0','192.168.0.23','24','192.168.255.255')
-    ip.addr.add('eth0','192.168.0.26','24')
-    ip.commit()
-    ip.route.add('eth0','192.168.0.0','24','192.168.0.1')
-    ip.route.add('eth0','192.168.0.5','24','192.168.0.1')
-    ip.commit()
-    ip.hop.delete('201.21.32.53','eth0')
-    ip.route.clear('eth0')
-    ip.commit()
-
-
-
diff --git a/services/ip/handler.py b/services/ip/handler.py
new file mode 100644 (file)
index 0000000..2bbc288
--- /dev/null
@@ -0,0 +1,376 @@
+# vim: set encoding=utf-8 et sw=4 sts=4 :
+
+from subprocess import Popen, PIPE
+from os import path
+import logging ; log = logging.getLogger('pymin.services.ip')
+
+from pymin.seqtools import Sequence
+from pymin.dispatcher import handler, HandlerError, Handler
+from pymin.service.util import Restorable, ConfigWriter, InitdHandler, \
+                               TransactionalHandler, SubHandler, call, \
+                               get_network_devices, ListComposedSubHandler, \
+                               DictComposedSubHandler, ListSubHandler, \
+                               Device, Address, ExecutionError
+
+__all__ = ('IpHandler', 'get_service')
+
+
+def get_service(config):
+    return IpHandler(config.ip.pickle_dir, config.ip.config_dir)
+
+
+class Hop(Sequence):
+
+    def __init__(self, gateway, device):
+        self.gateway = gateway
+        self.device = device
+
+    def as_tuple(self):
+        return (self.gateway, self.device)
+
+    def __cmp__(self, other):
+        if self.gateway == other.gateway \
+                and self.device == other.device:
+            return 0
+        return cmp(id(self), id(other))
+
+class HopHandler(ListSubHandler):
+    handler_help = u"Manage IP hops"
+    _cont_subhandler_attr = 'hops'
+    _cont_subhandler_class = Hop
+
+    @handler('Add a hop: add <device> <gateway>')
+    def add(self, dev, gw):
+        if not dev in self.parent.devices:
+            raise DeviceNotFoundError(device)
+        return ListSubHandler.add(self, dev, gw)
+
+
+class Route(Sequence):
+    def __init__(self, net_addr, prefix, gateway):
+        self.net_addr = net_addr
+        self.prefix = prefix
+        self.gateway = gateway
+
+    def update(self, net_addr=None, prefix=None, gateway=None):
+        if net_addr is not None: self.net_addr = net_addr
+        if prefix is not None: self.prefix = prefix
+        if gateway is not None: self.gateway = gateway
+
+    def as_tuple(self):
+        return(self.net_addr, self.prefix, self.gateway)
+
+    def __cmp__(self, other):
+        if self.net_addr == other.net_addr \
+                and self.prefix == other.prefix \
+                and self.gateway == other.gateway:
+            return 0
+        return cmp(id(self), id(other))
+
+class RouteHandler(ListComposedSubHandler):
+    handler_help = u"Manage IP routes"
+    _comp_subhandler_cont = 'devices'
+    _comp_subhandler_attr = 'routes'
+    _comp_subhandler_class = Route
+
+    @handler(u'Adds a route to : ip route add <net_addr> <prefix> <gateway> [device]')
+    def add(self, net_addr, prefix, gateway, dev=None):
+        if dev is not None:
+            ListComposedSubHandler.add(self, dev, net_addr, prefix, gateway)
+        else:
+            r = Route(net_addr, prefix, gateway)
+            if not r in self.parent.no_device_routes:
+                self.parent.no_device_routes.append(r)
+
+    @handler("Deletes a route : ip route delete <route_number_in_show> [dev]")
+    def delete(self, index, dev=None):
+        if dev is not None:
+            ListComposedSubHandler.delete(self, dev, index)
+        else:
+            i = int(index)
+            del self.parent.no_device_routes[i]
+
+    @handler("Shows routes : ip route show [dev]")
+    def show(self, dev=None):
+        if dev is not None:
+            return ListComposedSubHandler.show(self, dev)
+        else:
+            return self.parent.no_device_routes
+
+class AddressHandler(DictComposedSubHandler):
+    handler_help = u"Manage IP addresses"
+    _comp_subhandler_cont = 'devices'
+    _comp_subhandler_attr = 'addrs'
+    _comp_subhandler_class = Address
+
+
+class DeviceHandler(SubHandler):
+
+    handler_help = u"Manage network devices"
+
+    def __init__(self, parent):
+        log.debug(u'DeviceHandler(%r)', parent)
+        # FIXME remove templates to execute commands
+        from mako.template import Template
+        self.parent = parent
+        template_dir = path.join(path.dirname(__file__), 'templates')
+        dev_fn = path.join(template_dir, 'device')
+        self.device_template = Template(filename=dev_fn)
+
+    @handler(u'Bring the device up')
+    def up(self, name):
+        log.debug(u'DeviceHandler.up(%r)', name)
+        if name in self.parent.devices:
+            call(self.device_template.render(dev=name, action='up'), shell=True)
+            #bring up all the route asocitaed to the device
+            for route in self.parent.devices[name].routes:
+                try:
+                    log.debug(u'IpHandler.up: adding %r', route)
+                    call(self.parent._render_config('route_add', dict(
+                            dev = name,
+                            net_addr = route.net_addr,
+                            prefix = route.prefix,
+                            gateway = route.gateway,
+                        )
+                    ), shell=True)
+                except ExecutionError, e:
+                    log.debug(u'IpHandler.up: error adding %r -> %r', route, e)
+            self.parent._bring_up_no_dev_routes()
+            self.parent._restart_services()
+        else:
+            log.debug(u'DeviceHandler.up: device not found')
+            raise DeviceNotFoundError(name)
+
+    @handler(u'Bring the device down')
+    def down(self, name):
+        log.debug(u'DeviceHandler.down(%r)', name)
+        if name in self.parent.devices:
+            call(self.device_template.render(dev=name, action='down'), shell=True)
+            self.parent._bring_up_no_dev_routes()
+            self.parent._restart_services()
+        else:
+            log.debug(u'DeviceHandler.up: device not found')
+            raise DeviceNotFoundError(name)
+
+    @handler(u'List all devices')
+    def list(self):
+        log.debug(u'DeviceHandler.list()')
+        return self.parent.devices.keys()
+
+    @handler(u'Get information about a device')
+    def show(self):
+        log.debug(u'DeviceHandler.show()')
+        return self.parent.devices.items()
+
+class IpHandler(Restorable, ConfigWriter, TransactionalHandler):
+
+    handler_help = u"Manage IP devices, addresses, routes and hops"
+
+    _persistent_attrs = ('devices','hops','no_device_routes')
+
+    _restorable_defaults = dict(
+                            devices=get_network_devices(),
+                            hops = list(),
+                            no_device_routes = list(),
+                            )
+
+    _config_writer_files = ('device', 'ip_add', 'ip_del', 'ip_flush',
+                            'route_add', 'route_del', 'route_flush', 'hop')
+    _config_writer_tpl_dir = path.join(path.dirname(__file__), 'templates')
+
+    def __init__(self, pickle_dir='.', config_dir='.'):
+        r"Initialize DhcpHandler object, see class documentation for details."
+        log.debug(u'IpHandler(%r, %r)', pickle_dir, config_dir)
+        self._persistent_dir = pickle_dir
+        self._config_writer_cfg_dir = config_dir
+        self._config_build_templates()
+        self._restore()
+        self._write_config()
+        self.addr = AddressHandler(self)
+        self.route = RouteHandler(self)
+        self.dev = DeviceHandler(self)
+        self.hop = HopHandler(self)
+        self.no_device_routes = list()
+        self.services = list()
+
+    def _write_config(self):
+        r"_write_config() -> None :: Execute all commands."
+        log.debug(u'IpHandler._write_config()')
+        for device in self.devices.values():
+            log.debug(u'IpHandler._write_config: processing device %s', device)
+            if device.active:
+                self._write_config_for_device(device)
+        self._bring_up_no_dev_routes()
+        self._write_hops()
+
+    def _bring_up_no_dev_routes(self):
+        log.debug(u'IpHandler._bring_up_no_dev_routes()')
+        for route in self.no_device_routes:
+            try:
+                log.debug(u'IpHandler._bring_up_no_dev_routes: add %r', route)
+                call(self._render_config('route_add', dict(
+                        dev = None,
+                        net_addr = route.net_addr,
+                        prefix = route.prefix,
+                        gateway = route.gateway,
+                    )
+                ), shell=True)
+            except ExecutionError, e:
+                log.debug(u'IpHandler._write_config: error flushing -> %r', e)
+
+    def _write_hops(self):
+        r"_write_hops() -> None :: Execute all hops."
+        log.debug(u'IpHandler._write_hops()')
+        if self.hops:
+            log.debug(u'IpHandler._write_hops: we have hops: %r', self.hops)
+            try:
+                log.debug(u'IpHandler._write_hops: flushing default hops')
+                call('ip route del default', shell=True)
+            except ExecutionError, e:
+                log.debug(u'IpHandler._write_hops: error adding -> %r', e)
+            try:
+                log.debug(u'IpHandler._write_hops: configuring hops')
+                #get hops for active devices
+                active_hops = dict()
+                for h in self.hops:
+                    if h.device in self.devices:
+                        if self.devices[h.device].active:
+                            active_hops.append(h)
+                call(self._render_config('hop', dict(
+                    hops = active_hops,
+                        )
+                ), shell=True)
+            except ExecutionError, e:
+                log.debug(u'IpHandler._write_hops: error adding -> %r', e)
+
+    def _write_config_for_device(self, device):
+        r"_write_config_for_device(self, device) -> None :: Execute commands."
+        log.debug(u'IpHandler._write_config_for_device()')
+        try:
+            log.debug(u'IpHandler._write_config_for_device: flushing routes...')
+            call(self._render_config('route_flush', dict(dev=device.name)),
+                        shell=True)
+        except ExecutionError, e:
+            log.debug(u'IpHandler._write_config_for_device: error flushing '
+                        u'-> %r', e)
+        try:
+            log.debug(u'IpHandler._write_config_for_device: flushing addrs...')
+            call(self._render_config('ip_flush', dict(dev=device.name)),
+                        shell=True)
+        except ExecutionError, e:
+            log.debug(u'IpHandler._write_config_for_device: error flushing '
+                        u'-> %r', e)
+        for address in device.addrs.values():
+            broadcast = address.broadcast
+            if broadcast is None:
+                broadcast = '+'
+            try:
+                log.debug(u'IpHandler._write_config_for_device: adding %r',
+                            address)
+                call(self._render_config('ip_add', dict(
+                    dev = device.name,
+                    addr = address.ip,
+                    netmask = address.netmask,
+                    peer = address.peer,
+                    broadcast = broadcast,
+                    )
+                ), shell=True)
+            except ExecutionError, e:
+                log.debug(u'IpHandler._write_config_for_device: error adding '
+                            u'-> %r', e)
+        for route in device.routes:
+            try:
+                log.debug(u'IpHandler._write_config_for_device: adding %r',
+                            route)
+                call(self._render_config('route_add', dict(
+                        dev = device.name,
+                        net_addr = route.net_addr,
+                        prefix = route.prefix,
+                        gateway = route.gateway,
+                    )
+                ), shell=True)
+            except ExecutionError, e:
+                log.debug(u'IpHandler._write_config_for_device: error adding '
+                            u'-> %r', e)
+
+    def handle_timer(self):
+        log.debug(u'IpHandler.handle_timer()')
+        self.refresh_devices()
+
+    def refresh_devices(self):
+        log.debug(u'IpHandler.update_devices()')
+        devices = get_network_devices()
+        #add not registered and active devices
+        go_active = False
+        for k,v in devices.items():
+            if k not in self.devices:
+                log.debug(u'IpHandler.update_devices: adding %r', v)
+                self.devices[k] = v
+            elif not self.devices[k].active:
+                self.active = True
+                go_active = True
+                self._write_config_for_device(self.devices[k])
+        if go_active:
+            self._write_hops()
+            self._bring_up_no_dev_routes()
+            self._restart_services()
+
+        #mark inactive devices
+        for k in self.devices.keys():
+            go_down = False
+            if k not in devices:
+                log.debug(u'IpHandler.update_devices: removing %s', k)
+                self.devices[k].active = False
+                go_down = True
+            if go_down:
+                self._bring_up_no_dev_routes()
+
+    def _restart_services(self):
+        for s in self.services:
+            if s._service_running:
+                try:
+                     s.stop()
+                except ExecutionError:
+                    pass
+                try:
+                    s.start()
+                except ExecutionError:
+                    pass
+
+       #hooks a service to the ip handler, so when
+       #a device is brought up one can restart the service
+       #that need to refresh their device list
+    def device_up_hook(self, serv):
+        if hasattr(serv, 'stop') and hasattr(serv, 'start'):
+            self.services.append(serv)
+
+
+
+
+
+if __name__ == '__main__':
+
+    logging.basicConfig(
+        level   = logging.DEBUG,
+        format  = '%(asctime)s %(levelname)-8s %(message)s',
+        datefmt = '%H:%M:%S',
+    )
+
+    ip = IpHandler()
+    print '----------------------'
+    ip.hop.add('201.21.32.53','eth0')
+    ip.hop.add('205.65.65.25','eth1')
+    ip.commit()
+    ip.dev.up('eth0')
+    ip.addr.add('eth0','192.168.0.23','24','192.168.255.255')
+    ip.addr.add('eth0','192.168.0.26','24')
+    ip.commit()
+    ip.route.add('eth0','192.168.0.0','24','192.168.0.1')
+    ip.route.add('eth0','192.168.0.5','24','192.168.0.1')
+    ip.commit()
+    ip.hop.delete('201.21.32.53','eth0')
+    ip.route.clear('eth0')
+    ip.commit()
+
+
+
index 32e2608b930c11f2ddc3f65e3a3294c036377bc1..0deab9a7d1bb493875ea0c87a079acaa82bf7528 100644 (file)
@@ -1,285 +1,7 @@
 # vim: set encoding=utf-8 et sw=4 sts=4 :
 
-from os import path
-import logging ; log = logging.getLogger('pymin.services.nat')
-
-from pymin.seqtools import Sequence
-from pymin.dispatcher import Handler, handler, HandlerError
-from pymin.service.util import Restorable, ConfigWriter, RestartHandler, \
-                               ReloadHandler, TransactionalHandler, \
-                               ServiceHandler, ListSubHandler, call
-
-__all__ = ('NatHandler', 'get_service')
-
+from handler import NatHandler
 
 def get_service(config):
     return NatHandler(config.nat.pickle_dir)
 
-
-class PortForward(Sequence):
-    r"""PortForward(dev, protocol, port, dst[, dst_port[, ...]]) -> PortForward.
-
-    dev - Netword device to use.
-    protocol - TCP or UDP.
-    port - Port to forward.
-    dst - Destination IP address.
-    dst_port - Destination port (at dst).
-    src_net - Source network to apply the forward (as IP/mask).
-    dst_net - Source network to apply the forward (as IP/mask).
-    """
-
-    def __init__(self, dev, protocol, port, dst, dst_port=None, src_net=None,
-                       dst_net=None):
-        r"Initialize object, see class documentation for details."
-        # TODO Validate
-        self.dev = dev
-        self.protocol = protocol
-        self.port = port
-        self.dst = dst
-        self.dst_port = dst_port
-        self.src_net = src_net
-        self.dst_net = dst_net
-
-    def update(self, dev=None, protocol=None, port=None, dst=None,
-                    dst_port=None, src_net=None, dst_net=None):
-        r"update([dev[, ...]]) -> Update the values of a port (see class doc)."
-        # TODO Validate
-        if dev is not None: self.dev = dev
-        if protocol is not None: self.protocol = protocol
-        if port is not None: self.port = port
-        if dst is not None: self.dst = dst
-        if dst_port is not None: self.dst_port = dst_port
-        if src_net is not None: self.src_net = src_net
-        if dst_net is not None: self.dst_net = dst_net
-
-    def as_tuple(self):
-        r"Return a tuple representing the port forward."
-        return (self.dev, self.protocol, self.port, self.dst, self.dst_port,
-                    self.src_net, self.dst_net)
-
-    def as_call_list(self, index=None):
-        if self.dst_port is not None:
-            self.dst = self.dst + ':' + self.dst_port
-        cmd = ['-t', 'nat', '-I', 'PREROUTING']
-        if index is not None:
-            cmd.append(str(index))
-        cmd.extend(('-i', self.dev, '-j', 'DNAT', '--to', self.dst,
-                '-p', self.protocol, '--dport', self.port))
-        if self.src_net is not None:
-            cmd.extend(('-s', self.src_net))
-        if self.dst_net is not None:
-            cmd.extend(('-d', self.dst_net))
-        return cmd
-
-class PortForwardHandler(ListSubHandler):
-    r"""PortForwardHandler(parent) -> PortForwardHandler instance.
-
-    This class is a helper for NatHandler to do all the work related to port
-    forwarding.
-
-    parent - The parent service handler.
-    """
-
-    handler_help = u"Manage NAT port forwarding."
-
-    _cont_subhandler_attr = 'ports'
-    _cont_subhandler_class = PortForward
-
-class SNat(Sequence):
-    r"""SNat(dev, src[, src_net]) -> SNat instance.
-
-    dev - Netword device to use.
-    src - Source IP address.
-    src_net - Source network to apply the NAT (as IP/mask).
-    """
-
-    def __init__(self, dev, src, src_net=None):
-        r"Initialize object, see class documentation for details."
-        # TODO Validate
-        self.dev = dev
-        self.src = src
-        self.src_net = src_net
-
-    def update(self, dev=None, src=None, src_net=None):
-        r"update([dev[, ...]]) -> Update the values of a snat (see class doc)."
-        # TODO Validate
-        if dev is not None: self.dev = dev
-        if src is not None: self.src = src
-        if src_net is not None: self.src_net = src_net
-
-    def __cmp__(self, other):
-        r"Compares two SNat objects."
-        return cmp(self.as_tuple(), other.as_tuple())
-
-    def as_tuple(self):
-        r"Return a tuple representing the snat."
-        return (self.dev, self.src, self.src_net)
-
-    def as_call_list(self, index=None):
-        cmd = ['-t', 'nat', '-I', 'POSTROUTING']
-        if index is not None:
-            cmd.append(str(index))
-        cmd.extend(('-o', self.dev, '-j', 'SNAT', '--to', self.src))
-        if self.src_net is not None:
-            cmd.extend(('-s', self.src_net))
-        return cmd
-
-class SNatHandler(ListSubHandler):
-    r"""SNatHandler(parent) -> SNatHandler instance.
-
-    This class is a helper for NatHandler to do all the work related to
-    Source NAT.
-
-    parent - The parent service handler.
-    """
-
-    handler_help = u"Manage source NAT."
-
-    _cont_subhandler_attr = 'snats'
-    _cont_subhandler_class = SNat
-
-class Masq(Sequence):
-    r"""Masq(dev, src_net) -> Masq instance.
-
-    dev - Netword device to use.
-    src_net - Source network to apply the masquerade (as IP/mask).
-    """
-
-    def __init__(self, dev, src_net):
-        r"Initialize object, see class documentation for details."
-        # TODO Validate
-        self.dev = dev
-        self.src_net = src_net
-
-    def update(self, dev=None, src_net=None):
-        r"update([dev[, ...]]) -> Update the values of a masq (see class doc)."
-        # TODO Validate
-        if dev is not None: self.dev = dev
-        if src_net is not None: self.src_net = src_net
-
-    def __cmp__(self, other):
-        r"Compares two Masq objects."
-        return cmp(self.as_tuple(), other.as_tuple())
-
-    def as_tuple(self):
-        r"Return a tuple representing the masquerade."
-        return (self.dev, self.src_net)
-
-    def as_call_list(self, index=None):
-        cmd = ['-t', 'nat', '-I', 'POSTROUTING']
-        if index is not None:
-            cmd.append(str(index))
-        cmd.extend(('-o', self.dev, '-j', 'MASQUERADE', '-s', self.src_net))
-        return cmd
-
-class MasqHandler(ListSubHandler):
-    r"""MasqHandler(parent) -> MasqHandler instance.
-
-    This class is a helper for NatHandler to do all the work related to
-    masquerading.
-
-    parent - The parent service handler.
-    """
-
-    handler_help = u"Manage NAT masquerading."
-
-    _cont_subhandler_attr = 'masqs'
-    _cont_subhandler_class = Masq
-
-class NatHandler(Restorable, ConfigWriter, ReloadHandler, ServiceHandler,
-                        TransactionalHandler):
-    r"""NatHandler([pickle_dir[, config_dir]]) -> NatHandler instance.
-
-    Handles NAT commands using iptables.
-
-    pickle_dir - Directory where to write the persistent configuration data.
-
-    config_dir - Directory where to store de generated configuration files.
-
-    Both defaults to the current working directory.
-    """
-
-    handler_help = u"Manage NAT (Network Address Translation) service."
-
-    _persistent_attrs = ('ports', 'snats', 'masqs')
-
-    _restorable_defaults = dict(
-        ports=list(),
-        snats=list(),
-        masqs=list(),
-    )
-
-    def _service_start(self):
-        log.debug(u'NatHandler._service_start(): flushing nat table')
-        call(('iptables', '-t', 'nat', '-F'))
-        for (index, port) in enumerate(self.ports):
-            log.debug(u'NatHandler._service_start: adding port %r', port)
-            call(['iptables'] + port.as_call_list(index+1))
-        for (index, snat) in enumerate(self.snats):
-            log.debug(u'NatHandler._service_start: adding snat %r', snat)
-            call(['iptables'] + snat.as_call_list(index+1))
-        for (index, masq) in enumerate(self.masqs):
-            log.debug(u'NatHandler._service_start: adding masq %r', masq)
-            call(['iptables'] + masq.as_call_list(index+1))
-
-    def _service_stop(self):
-        log.debug(u'NatHandler._service_stop(): flushing nat table')
-        call(('iptables', '-t', 'nat', '-F'))
-
-    _service_restart = _service_start
-
-    def __init__(self, pickle_dir='.'):
-        r"Initialize the object, see class documentation for details."
-        log.debug(u'NatHandler(%r)', pickle_dir)
-        self._persistent_dir = pickle_dir
-        ServiceHandler.__init__(self)
-        self.forward = PortForwardHandler(self)
-        self.snat = SNatHandler(self)
-        self.masq = MasqHandler(self)
-
-
-if __name__ == '__main__':
-
-    logging.basicConfig(
-        level   = logging.DEBUG,
-        format  = '%(asctime)s %(levelname)-8s %(message)s',
-        datefmt = '%H:%M:%S',
-    )
-
-    import os
-
-    handler = NatHandler()
-
-    def dump():
-        print '-' * 80
-        print 'Forwarded ports:'
-        print handler.forward.show()
-        print '-' * 10
-        print 'SNat:'
-        print handler.snat.show()
-        print '-' * 10
-        print 'Masq:'
-        print handler.masq.show()
-        print '-' * 80
-
-    dump()
-    handler.forward.add('eth0','tcp','80', '192.168.0.9', '8080')
-    handler.forward.update(0, dst_net='192.168.0.188/32')
-    handler.forward.add('eth0', 'udp', '53', '192.168.1.0')
-    handler.commit()
-    handler.stop()
-    dump()
-    handler.snat.add('eth0', '192.168.0.9')
-    handler.snat.update(0, src_net='192.168.0.188/32')
-    handler.snat.add('eth0', '192.168.1.0')
-    handler.commit()
-    dump()
-    dump()
-    handler.masq.add('eth0', '192.168.0.9/24')
-    handler.masq.update(0, src_net='192.168.0.188/30')
-    handler.masq.add('eth1', '192.168.1.0/24')
-    handler.commit()
-    dump()
-
-    os.system('rm -f *.pkl')
-
diff --git a/services/nat/handler.py b/services/nat/handler.py
new file mode 100644 (file)
index 0000000..32e2608
--- /dev/null
@@ -0,0 +1,285 @@
+# vim: set encoding=utf-8 et sw=4 sts=4 :
+
+from os import path
+import logging ; log = logging.getLogger('pymin.services.nat')
+
+from pymin.seqtools import Sequence
+from pymin.dispatcher import Handler, handler, HandlerError
+from pymin.service.util import Restorable, ConfigWriter, RestartHandler, \
+                               ReloadHandler, TransactionalHandler, \
+                               ServiceHandler, ListSubHandler, call
+
+__all__ = ('NatHandler', 'get_service')
+
+
+def get_service(config):
+    return NatHandler(config.nat.pickle_dir)
+
+
+class PortForward(Sequence):
+    r"""PortForward(dev, protocol, port, dst[, dst_port[, ...]]) -> PortForward.
+
+    dev - Netword device to use.
+    protocol - TCP or UDP.
+    port - Port to forward.
+    dst - Destination IP address.
+    dst_port - Destination port (at dst).
+    src_net - Source network to apply the forward (as IP/mask).
+    dst_net - Source network to apply the forward (as IP/mask).
+    """
+
+    def __init__(self, dev, protocol, port, dst, dst_port=None, src_net=None,
+                       dst_net=None):
+        r"Initialize object, see class documentation for details."
+        # TODO Validate
+        self.dev = dev
+        self.protocol = protocol
+        self.port = port
+        self.dst = dst
+        self.dst_port = dst_port
+        self.src_net = src_net
+        self.dst_net = dst_net
+
+    def update(self, dev=None, protocol=None, port=None, dst=None,
+                    dst_port=None, src_net=None, dst_net=None):
+        r"update([dev[, ...]]) -> Update the values of a port (see class doc)."
+        # TODO Validate
+        if dev is not None: self.dev = dev
+        if protocol is not None: self.protocol = protocol
+        if port is not None: self.port = port
+        if dst is not None: self.dst = dst
+        if dst_port is not None: self.dst_port = dst_port
+        if src_net is not None: self.src_net = src_net
+        if dst_net is not None: self.dst_net = dst_net
+
+    def as_tuple(self):
+        r"Return a tuple representing the port forward."
+        return (self.dev, self.protocol, self.port, self.dst, self.dst_port,
+                    self.src_net, self.dst_net)
+
+    def as_call_list(self, index=None):
+        if self.dst_port is not None:
+            self.dst = self.dst + ':' + self.dst_port
+        cmd = ['-t', 'nat', '-I', 'PREROUTING']
+        if index is not None:
+            cmd.append(str(index))
+        cmd.extend(('-i', self.dev, '-j', 'DNAT', '--to', self.dst,
+                '-p', self.protocol, '--dport', self.port))
+        if self.src_net is not None:
+            cmd.extend(('-s', self.src_net))
+        if self.dst_net is not None:
+            cmd.extend(('-d', self.dst_net))
+        return cmd
+
+class PortForwardHandler(ListSubHandler):
+    r"""PortForwardHandler(parent) -> PortForwardHandler instance.
+
+    This class is a helper for NatHandler to do all the work related to port
+    forwarding.
+
+    parent - The parent service handler.
+    """
+
+    handler_help = u"Manage NAT port forwarding."
+
+    _cont_subhandler_attr = 'ports'
+    _cont_subhandler_class = PortForward
+
+class SNat(Sequence):
+    r"""SNat(dev, src[, src_net]) -> SNat instance.
+
+    dev - Netword device to use.
+    src - Source IP address.
+    src_net - Source network to apply the NAT (as IP/mask).
+    """
+
+    def __init__(self, dev, src, src_net=None):
+        r"Initialize object, see class documentation for details."
+        # TODO Validate
+        self.dev = dev
+        self.src = src
+        self.src_net = src_net
+
+    def update(self, dev=None, src=None, src_net=None):
+        r"update([dev[, ...]]) -> Update the values of a snat (see class doc)."
+        # TODO Validate
+        if dev is not None: self.dev = dev
+        if src is not None: self.src = src
+        if src_net is not None: self.src_net = src_net
+
+    def __cmp__(self, other):
+        r"Compares two SNat objects."
+        return cmp(self.as_tuple(), other.as_tuple())
+
+    def as_tuple(self):
+        r"Return a tuple representing the snat."
+        return (self.dev, self.src, self.src_net)
+
+    def as_call_list(self, index=None):
+        cmd = ['-t', 'nat', '-I', 'POSTROUTING']
+        if index is not None:
+            cmd.append(str(index))
+        cmd.extend(('-o', self.dev, '-j', 'SNAT', '--to', self.src))
+        if self.src_net is not None:
+            cmd.extend(('-s', self.src_net))
+        return cmd
+
+class SNatHandler(ListSubHandler):
+    r"""SNatHandler(parent) -> SNatHandler instance.
+
+    This class is a helper for NatHandler to do all the work related to
+    Source NAT.
+
+    parent - The parent service handler.
+    """
+
+    handler_help = u"Manage source NAT."
+
+    _cont_subhandler_attr = 'snats'
+    _cont_subhandler_class = SNat
+
+class Masq(Sequence):
+    r"""Masq(dev, src_net) -> Masq instance.
+
+    dev - Netword device to use.
+    src_net - Source network to apply the masquerade (as IP/mask).
+    """
+
+    def __init__(self, dev, src_net):
+        r"Initialize object, see class documentation for details."
+        # TODO Validate
+        self.dev = dev
+        self.src_net = src_net
+
+    def update(self, dev=None, src_net=None):
+        r"update([dev[, ...]]) -> Update the values of a masq (see class doc)."
+        # TODO Validate
+        if dev is not None: self.dev = dev
+        if src_net is not None: self.src_net = src_net
+
+    def __cmp__(self, other):
+        r"Compares two Masq objects."
+        return cmp(self.as_tuple(), other.as_tuple())
+
+    def as_tuple(self):
+        r"Return a tuple representing the masquerade."
+        return (self.dev, self.src_net)
+
+    def as_call_list(self, index=None):
+        cmd = ['-t', 'nat', '-I', 'POSTROUTING']
+        if index is not None:
+            cmd.append(str(index))
+        cmd.extend(('-o', self.dev, '-j', 'MASQUERADE', '-s', self.src_net))
+        return cmd
+
+class MasqHandler(ListSubHandler):
+    r"""MasqHandler(parent) -> MasqHandler instance.
+
+    This class is a helper for NatHandler to do all the work related to
+    masquerading.
+
+    parent - The parent service handler.
+    """
+
+    handler_help = u"Manage NAT masquerading."
+
+    _cont_subhandler_attr = 'masqs'
+    _cont_subhandler_class = Masq
+
+class NatHandler(Restorable, ConfigWriter, ReloadHandler, ServiceHandler,
+                        TransactionalHandler):
+    r"""NatHandler([pickle_dir[, config_dir]]) -> NatHandler instance.
+
+    Handles NAT commands using iptables.
+
+    pickle_dir - Directory where to write the persistent configuration data.
+
+    config_dir - Directory where to store de generated configuration files.
+
+    Both defaults to the current working directory.
+    """
+
+    handler_help = u"Manage NAT (Network Address Translation) service."
+
+    _persistent_attrs = ('ports', 'snats', 'masqs')
+
+    _restorable_defaults = dict(
+        ports=list(),
+        snats=list(),
+        masqs=list(),
+    )
+
+    def _service_start(self):
+        log.debug(u'NatHandler._service_start(): flushing nat table')
+        call(('iptables', '-t', 'nat', '-F'))
+        for (index, port) in enumerate(self.ports):
+            log.debug(u'NatHandler._service_start: adding port %r', port)
+            call(['iptables'] + port.as_call_list(index+1))
+        for (index, snat) in enumerate(self.snats):
+            log.debug(u'NatHandler._service_start: adding snat %r', snat)
+            call(['iptables'] + snat.as_call_list(index+1))
+        for (index, masq) in enumerate(self.masqs):
+            log.debug(u'NatHandler._service_start: adding masq %r', masq)
+            call(['iptables'] + masq.as_call_list(index+1))
+
+    def _service_stop(self):
+        log.debug(u'NatHandler._service_stop(): flushing nat table')
+        call(('iptables', '-t', 'nat', '-F'))
+
+    _service_restart = _service_start
+
+    def __init__(self, pickle_dir='.'):
+        r"Initialize the object, see class documentation for details."
+        log.debug(u'NatHandler(%r)', pickle_dir)
+        self._persistent_dir = pickle_dir
+        ServiceHandler.__init__(self)
+        self.forward = PortForwardHandler(self)
+        self.snat = SNatHandler(self)
+        self.masq = MasqHandler(self)
+
+
+if __name__ == '__main__':
+
+    logging.basicConfig(
+        level   = logging.DEBUG,
+        format  = '%(asctime)s %(levelname)-8s %(message)s',
+        datefmt = '%H:%M:%S',
+    )
+
+    import os
+
+    handler = NatHandler()
+
+    def dump():
+        print '-' * 80
+        print 'Forwarded ports:'
+        print handler.forward.show()
+        print '-' * 10
+        print 'SNat:'
+        print handler.snat.show()
+        print '-' * 10
+        print 'Masq:'
+        print handler.masq.show()
+        print '-' * 80
+
+    dump()
+    handler.forward.add('eth0','tcp','80', '192.168.0.9', '8080')
+    handler.forward.update(0, dst_net='192.168.0.188/32')
+    handler.forward.add('eth0', 'udp', '53', '192.168.1.0')
+    handler.commit()
+    handler.stop()
+    dump()
+    handler.snat.add('eth0', '192.168.0.9')
+    handler.snat.update(0, src_net='192.168.0.188/32')
+    handler.snat.add('eth0', '192.168.1.0')
+    handler.commit()
+    dump()
+    dump()
+    handler.masq.add('eth0', '192.168.0.9/24')
+    handler.masq.update(0, src_net='192.168.0.188/30')
+    handler.masq.add('eth1', '192.168.1.0/24')
+    handler.commit()
+    dump()
+
+    os.system('rm -f *.pkl')
+
index 9c6bdff6db22d31a1e8372bf31e7e381035ba845..cc53450753a5578b8b4d71cf525a08ccf30ddcd3 100644 (file)
@@ -1,245 +1,7 @@
 # vim: set encoding=utf-8 et sw=4 sts=4 :
 
-import os
-import subprocess
-from os import path
-from signal import SIGTERM
-import logging ; log = logging.getLogger('pymin.services.ppp')
-
-from pymin.seqtools import Sequence
-from pymin.dispatcher import Handler, handler, HandlerError
-from pymin.service.util import Restorable, ConfigWriter, ReloadHandler, \
-                               TransactionalHandler, DictSubHandler, call
-
-__all__ = ('PppHandler', 'get_service')
-
+from handler import PppHandler
 
 def get_service(config):
     return PppHandler(config.ppp.pickle_dir, config.ppp.config_dir)
 
-
-class ConnectionError(HandlerError, KeyError):
-    r"""
-    ConnectionError(hostname) -> ConnectionError instance
-
-    This is the base exception for all connection related errors.
-    """
-
-    def __init__(self, connection):
-        r"Initialize the object. See class documentation for more info."
-        self.message = u'Connection error: "%s"' % connection
-
-class ConnectionNotFoundError(ConnectionError):
-    def __init__(self, connection):
-        r"Initialize the object. See class documentation for more info."
-        self.message = u'Connection not found error: "%s"' % connection
-
-class Connection(Sequence):
-
-    def __init__(self, name, username, password, type, **kw):
-        self.name = name
-        self.username = username
-        self.password = password
-        self.type = type
-        self._running = False
-        if type == 'OE':
-            if not 'device' in kw:
-                raise ConnectionError('Bad arguments for type=OE')
-            self.device = kw['device']
-        elif type == 'TUNNEL':
-            if not 'server' in kw:
-                raise ConnectionError('Bad arguments for type=TUNNEL')
-            self.server = kw['server']
-            self.username = self.username.replace('\\','\\\\')
-        elif type == 'PPP':
-            if not 'device' in kw:
-                raise ConnectionError('Bad arguments for type=PPP')
-            self.device = kw['device']
-        else:
-            raise ConnectionError('Bad arguments, unknown or unspecified type')
-
-    def as_tuple(self):
-        if self.type == 'TUNNEL':
-            return (self.name, self.username, self.password, self.type, self.server)
-        elif self.type == 'PPP' or self.type == 'OE':
-            return (self.name, self.username, self.password, self.type, self.device)
-
-    def update(self, device=None, username=None, password=None):
-        if device is not None:
-            self.device = device
-        if username is not None:
-            self.username = username
-        if password is not None:
-            self.password = password
-
-
-class ConnectionHandler(DictSubHandler):
-
-    handler_help = u"Manages connections for the ppp service"
-
-    _cont_subhandler_attr = 'conns'
-    _cont_subhandler_class = Connection
-
-class PppHandler(Restorable, ConfigWriter, ReloadHandler, TransactionalHandler):
-
-    handler_help = u"Manage ppp service"
-
-    _persistent_attrs = ['conns']
-
-    _restorable_defaults = dict(
-        conns  = dict(),
-    )
-
-    _config_writer_files = ('options.X','pap-secrets','chap-secrets','nameX')
-    _config_writer_tpl_dir = path.join(path.dirname(__file__), 'templates')
-
-    def __init__(self, pickle_dir='.', config_dir='.'):
-        r"Initialize Ppphandler object, see class documentation for details."
-        log.debug(u'PppHandler(%r, %r)', pickle_dir, config_dir)
-        self._persistent_dir = pickle_dir
-        self._config_writer_cfg_dir = config_dir
-        self._config_build_templates()
-        self._restore()
-        log.debug(u'PppHandler(): restoring connections...')
-        for conn in self.conns.values():
-            if conn._running:
-                log.debug(u'PppHandler(): starting connection %r', conn.name)
-                conn._running = False
-                self.start(conn.name)
-        self.conn = ConnectionHandler(self)
-
-    @handler(u'Start one or all the connections.')
-    def start(self, name=None):
-        log.debug(u'PppHandler.start(%r)', name)
-        names = [name]
-        if name is None:
-            names = self.conns.keys()
-        for name in names:
-            if name in self.conns:
-                if not self.conns[name]._running:
-                    log.debug(u'PppHandler.start: starting connection %r', name)
-                    call(('pppd', 'call', name))
-                    self.conns[name]._running = True
-                    self._dump_attr('conns')
-            else:
-                log.debug(u'PppHandler.start: connection not found')
-                raise ConnectionNotFoundError(name)
-
-    @handler(u'Stop one or all the connections.')
-    def stop(self, name=None):
-        log.debug(u'PppHandler.stop(%r)', name)
-        names = [name]
-        names = [name]
-        if name is None:
-            names = self.conns.keys()
-        for name in names:
-            if name in self.conns:
-                if self.conns[name]._running:
-                    pid_file = '/var/run/ppp-' + name + '.pid'
-                    log.debug(u'PppHandler.stop: getting pid from %r', pid_file)
-                    if path.exists(pid_file):
-                        pid = file(pid_file).readline()
-                        pid = int(pid.strip())
-                        try:
-                            log.debug(u'PppHandler.stop: killing pid %r', pid)
-                            os.kill(pid, SIGTERM)
-                        except OSError, e:
-                            log.debug(u'PppHandler.stop: error killing: %r', e)
-                    else:
-                        log.debug(u'PppHandler.stop: pid file not found')
-                    self.conns[name]._running = False
-                    self._dump_attr('conns')
-                else:
-                    log.debug(u'PppHandler.stop: connection not running')
-            else:
-                log.debug(u'PppHandler.stop: connection not found')
-                raise ConnectionNotFoundError(name)
-
-    @handler(u'Restart one or all the connections (even disconnected ones).')
-    def restart(self, name=None):
-        log.debug(u'PppHandler.restart(%r)', name)
-        names = [name]
-        if name is None:
-            names = self.conns.keys()
-        for name in names:
-            self.stop(name)
-            self.start(name)
-
-    @handler(u'Restart only one or all the already running connections.')
-    def reload(self, name=None):
-        r"reload() -> None :: Reload the configuration of the service."
-        log.debug(u'PppHandler.reload(%r)', name)
-        names = [name]
-        if name is None:
-            names = self.conns.keys()
-        for name in names:
-            if self.conns[name]._running:
-                self.stop(name)
-                self.start(name)
-
-    @handler(u'Tell if the service is running.')
-    def running(self, name=None):
-        r"reload() -> None :: Reload the configuration of the service."
-        log.debug(u'PppHandler.running(%r)', name)
-        if name is None:
-            return [c.name for c in self.conns.values() if c._running]
-        if name in self.conns:
-            return int(self.conns[name]._running)
-        else:
-            log.debug(u'PppHandler.running: connection not found')
-            raise ConnectionNotFoundError(name)
-
-    def handle_timer(self):
-        log.debug(u'PppHandler.handle_timer()')
-        for c in self.conns.values():
-            log.debug(u'PppHandler.handle_timer: processing connection %r', c)
-            p = subprocess.Popen(('pgrep', '-f', 'pppd call ' + c.name),
-                                    stdout=subprocess.PIPE)
-            pid = p.communicate()[0]
-            if p.returncode == 0 and len(pid) > 0:
-                log.debug(u'PppHandler.handle_timer: pid present, running')
-                c._running = True
-            else:
-                log.debug(u'PppHandler.handle_timer: pid absent, NOT running')
-                c._running = False
-
-    def _write_config(self):
-        r"_write_config() -> None :: Generate all the configuration files."
-        log.debug(u'PppHandler._write_config()')
-        #guardo los pass que van el pap-secrets
-        vars_pap = dict()
-        for conn in self.conns.values():
-            if conn.type == 'OE' or conn.type == 'PPP':
-                vars_pap[conn.name] = conn
-        vars = dict(conns=vars_pap)
-        self._write_single_config('pap-secrets','pap-secrets',vars)
-        #guardo los pass que van el chap-secrets
-        vars_chap = dict()
-        for conn in self.conns.values():
-            if conn.type == 'TUNNEL' :
-                vars_chap[conn.name] = conn
-        vars = dict(conns=vars_chap)
-        self._write_single_config('chap-secrets','chap-secrets',vars)
-        #guard las conns
-        for conn in self.conns.values():
-            vars = dict(conn=conn)
-            self._write_single_config('nameX',conn.name, vars)
-            self._write_single_config('options.X','options.' + conn.name, vars)
-
-
-if __name__ == '__main__':
-
-    logging.basicConfig(
-        level   = logging.DEBUG,
-        format  = '%(asctime)s %(levelname)-8s %(message)s',
-        datefmt = '%H:%M:%S',
-    )
-
-    p = PppHandler()
-    p.conn.add('ppp_c','nico','nico',type='PPP',device='tty0')
-    p.conn.add('pppoe_c','fede','fede',type='OE',device='tty1')
-    p.conn.add('ppptunnel_c','dominio\luca','luca',type='TUNNEL',server='192.168.0.23')
-    p.commit()
-    print p.conn.list()
-    print p.conn.show()
-
diff --git a/services/ppp/handler.py b/services/ppp/handler.py
new file mode 100644 (file)
index 0000000..9c6bdff
--- /dev/null
@@ -0,0 +1,245 @@
+# vim: set encoding=utf-8 et sw=4 sts=4 :
+
+import os
+import subprocess
+from os import path
+from signal import SIGTERM
+import logging ; log = logging.getLogger('pymin.services.ppp')
+
+from pymin.seqtools import Sequence
+from pymin.dispatcher import Handler, handler, HandlerError
+from pymin.service.util import Restorable, ConfigWriter, ReloadHandler, \
+                               TransactionalHandler, DictSubHandler, call
+
+__all__ = ('PppHandler', 'get_service')
+
+
+def get_service(config):
+    return PppHandler(config.ppp.pickle_dir, config.ppp.config_dir)
+
+
+class ConnectionError(HandlerError, KeyError):
+    r"""
+    ConnectionError(hostname) -> ConnectionError instance
+
+    This is the base exception for all connection related errors.
+    """
+
+    def __init__(self, connection):
+        r"Initialize the object. See class documentation for more info."
+        self.message = u'Connection error: "%s"' % connection
+
+class ConnectionNotFoundError(ConnectionError):
+    def __init__(self, connection):
+        r"Initialize the object. See class documentation for more info."
+        self.message = u'Connection not found error: "%s"' % connection
+
+class Connection(Sequence):
+
+    def __init__(self, name, username, password, type, **kw):
+        self.name = name
+        self.username = username
+        self.password = password
+        self.type = type
+        self._running = False
+        if type == 'OE':
+            if not 'device' in kw:
+                raise ConnectionError('Bad arguments for type=OE')
+            self.device = kw['device']
+        elif type == 'TUNNEL':
+            if not 'server' in kw:
+                raise ConnectionError('Bad arguments for type=TUNNEL')
+            self.server = kw['server']
+            self.username = self.username.replace('\\','\\\\')
+        elif type == 'PPP':
+            if not 'device' in kw:
+                raise ConnectionError('Bad arguments for type=PPP')
+            self.device = kw['device']
+        else:
+            raise ConnectionError('Bad arguments, unknown or unspecified type')
+
+    def as_tuple(self):
+        if self.type == 'TUNNEL':
+            return (self.name, self.username, self.password, self.type, self.server)
+        elif self.type == 'PPP' or self.type == 'OE':
+            return (self.name, self.username, self.password, self.type, self.device)
+
+    def update(self, device=None, username=None, password=None):
+        if device is not None:
+            self.device = device
+        if username is not None:
+            self.username = username
+        if password is not None:
+            self.password = password
+
+
+class ConnectionHandler(DictSubHandler):
+
+    handler_help = u"Manages connections for the ppp service"
+
+    _cont_subhandler_attr = 'conns'
+    _cont_subhandler_class = Connection
+
+class PppHandler(Restorable, ConfigWriter, ReloadHandler, TransactionalHandler):
+
+    handler_help = u"Manage ppp service"
+
+    _persistent_attrs = ['conns']
+
+    _restorable_defaults = dict(
+        conns  = dict(),
+    )
+
+    _config_writer_files = ('options.X','pap-secrets','chap-secrets','nameX')
+    _config_writer_tpl_dir = path.join(path.dirname(__file__), 'templates')
+
+    def __init__(self, pickle_dir='.', config_dir='.'):
+        r"Initialize Ppphandler object, see class documentation for details."
+        log.debug(u'PppHandler(%r, %r)', pickle_dir, config_dir)
+        self._persistent_dir = pickle_dir
+        self._config_writer_cfg_dir = config_dir
+        self._config_build_templates()
+        self._restore()
+        log.debug(u'PppHandler(): restoring connections...')
+        for conn in self.conns.values():
+            if conn._running:
+                log.debug(u'PppHandler(): starting connection %r', conn.name)
+                conn._running = False
+                self.start(conn.name)
+        self.conn = ConnectionHandler(self)
+
+    @handler(u'Start one or all the connections.')
+    def start(self, name=None):
+        log.debug(u'PppHandler.start(%r)', name)
+        names = [name]
+        if name is None:
+            names = self.conns.keys()
+        for name in names:
+            if name in self.conns:
+                if not self.conns[name]._running:
+                    log.debug(u'PppHandler.start: starting connection %r', name)
+                    call(('pppd', 'call', name))
+                    self.conns[name]._running = True
+                    self._dump_attr('conns')
+            else:
+                log.debug(u'PppHandler.start: connection not found')
+                raise ConnectionNotFoundError(name)
+
+    @handler(u'Stop one or all the connections.')
+    def stop(self, name=None):
+        log.debug(u'PppHandler.stop(%r)', name)
+        names = [name]
+        names = [name]
+        if name is None:
+            names = self.conns.keys()
+        for name in names:
+            if name in self.conns:
+                if self.conns[name]._running:
+                    pid_file = '/var/run/ppp-' + name + '.pid'
+                    log.debug(u'PppHandler.stop: getting pid from %r', pid_file)
+                    if path.exists(pid_file):
+                        pid = file(pid_file).readline()
+                        pid = int(pid.strip())
+                        try:
+                            log.debug(u'PppHandler.stop: killing pid %r', pid)
+                            os.kill(pid, SIGTERM)
+                        except OSError, e:
+                            log.debug(u'PppHandler.stop: error killing: %r', e)
+                    else:
+                        log.debug(u'PppHandler.stop: pid file not found')
+                    self.conns[name]._running = False
+                    self._dump_attr('conns')
+                else:
+                    log.debug(u'PppHandler.stop: connection not running')
+            else:
+                log.debug(u'PppHandler.stop: connection not found')
+                raise ConnectionNotFoundError(name)
+
+    @handler(u'Restart one or all the connections (even disconnected ones).')
+    def restart(self, name=None):
+        log.debug(u'PppHandler.restart(%r)', name)
+        names = [name]
+        if name is None:
+            names = self.conns.keys()
+        for name in names:
+            self.stop(name)
+            self.start(name)
+
+    @handler(u'Restart only one or all the already running connections.')
+    def reload(self, name=None):
+        r"reload() -> None :: Reload the configuration of the service."
+        log.debug(u'PppHandler.reload(%r)', name)
+        names = [name]
+        if name is None:
+            names = self.conns.keys()
+        for name in names:
+            if self.conns[name]._running:
+                self.stop(name)
+                self.start(name)
+
+    @handler(u'Tell if the service is running.')
+    def running(self, name=None):
+        r"reload() -> None :: Reload the configuration of the service."
+        log.debug(u'PppHandler.running(%r)', name)
+        if name is None:
+            return [c.name for c in self.conns.values() if c._running]
+        if name in self.conns:
+            return int(self.conns[name]._running)
+        else:
+            log.debug(u'PppHandler.running: connection not found')
+            raise ConnectionNotFoundError(name)
+
+    def handle_timer(self):
+        log.debug(u'PppHandler.handle_timer()')
+        for c in self.conns.values():
+            log.debug(u'PppHandler.handle_timer: processing connection %r', c)
+            p = subprocess.Popen(('pgrep', '-f', 'pppd call ' + c.name),
+                                    stdout=subprocess.PIPE)
+            pid = p.communicate()[0]
+            if p.returncode == 0 and len(pid) > 0:
+                log.debug(u'PppHandler.handle_timer: pid present, running')
+                c._running = True
+            else:
+                log.debug(u'PppHandler.handle_timer: pid absent, NOT running')
+                c._running = False
+
+    def _write_config(self):
+        r"_write_config() -> None :: Generate all the configuration files."
+        log.debug(u'PppHandler._write_config()')
+        #guardo los pass que van el pap-secrets
+        vars_pap = dict()
+        for conn in self.conns.values():
+            if conn.type == 'OE' or conn.type == 'PPP':
+                vars_pap[conn.name] = conn
+        vars = dict(conns=vars_pap)
+        self._write_single_config('pap-secrets','pap-secrets',vars)
+        #guardo los pass que van el chap-secrets
+        vars_chap = dict()
+        for conn in self.conns.values():
+            if conn.type == 'TUNNEL' :
+                vars_chap[conn.name] = conn
+        vars = dict(conns=vars_chap)
+        self._write_single_config('chap-secrets','chap-secrets',vars)
+        #guard las conns
+        for conn in self.conns.values():
+            vars = dict(conn=conn)
+            self._write_single_config('nameX',conn.name, vars)
+            self._write_single_config('options.X','options.' + conn.name, vars)
+
+
+if __name__ == '__main__':
+
+    logging.basicConfig(
+        level   = logging.DEBUG,
+        format  = '%(asctime)s %(levelname)-8s %(message)s',
+        datefmt = '%H:%M:%S',
+    )
+
+    p = PppHandler()
+    p.conn.add('ppp_c','nico','nico',type='PPP',device='tty0')
+    p.conn.add('pppoe_c','fede','fede',type='OE',device='tty1')
+    p.conn.add('ppptunnel_c','dominio\luca','luca',type='TUNNEL',server='192.168.0.23')
+    p.commit()
+    print p.conn.list()
+    print p.conn.show()
+
index 7a5272476bf4f9a0a27fcc2910931b32af2f9cfc..ab2e84cce2f959f6d78c29154c55d99bddd94a57 100644 (file)
@@ -1,108 +1,7 @@
 # vim: set encoding=utf-8 et sw=4 sts=4 :
 
-from os import path
-import logging ; log = logging.getLogger('pymin.services.proxy')
-
-from pymin.seqtools import Sequence
-from pymin.dispatcher import Handler, handler, HandlerError
-from pymin.service.util import Restorable, ConfigWriter, InitdHandler, \
-                               TransactionalHandler, ParametersHandler, \
-                               DictSubHandler
-
-import crypt
-
-
-__all__ = ('ProxyHandler', 'get_service')
-
+from handler import ProxyHandler
 
 def get_service(config):
     return ProxyHandler(config.proxy.pickle_dir, config.proxy.config_dir)
 
-
-class Host(Sequence):
-    def __init__(self,ip):
-        self.ip = ip
-    def as_tuple(self):
-        return (self.ip,)
-
-# TODO convert to a SetSubHandler
-
-class HostHandler(DictSubHandler):
-
-    handler_help = u"Manage proxy hosts"
-
-    _cont_subhandler_attr = 'hosts'
-    _cont_subhandler_class = Host
-
-class User(Sequence):
-    def __init__(self, name, password):
-        self.name = name
-        self.password = crypt.crypt(password,'BA')
-    def as_tuple(self):
-        return (self.name, self.password)
-    def update(self, password=None):
-        if password is not None:
-            self.password = crypt.crypt(password,'BA')
-
-class UserHandler(DictSubHandler):
-
-    handler_help = u"Manage proxy users"
-
-    _cont_subhandler_attr = 'users'
-    _cont_subhandler_class = User
-
-class ProxyHandler(Restorable, ConfigWriter, InitdHandler,
-                   TransactionalHandler, ParametersHandler):
-
-    handler_help = u"Manage proxy service"
-
-    _initd_name = 'squid'
-
-    _persistent_attrs = ('params', 'hosts', 'users')
-
-    _restorable_defaults = dict(
-            hosts = dict(),
-            params  = dict(
-                ip   = '192.168.0.1',
-                port = '8080',
-            ),
-            users = dict(),
-    )
-
-    _config_writer_files = ('squid.conf','users.conf')
-    _config_writer_tpl_dir = path.join(path.dirname(__file__), 'templates')
-
-    def __init__(self, pickle_dir='.', config_dir='.'):
-        r"Initialize DhcpHandler object, see class documentation for details."
-        log.debug(u'ProxyHandler(%r, %r)', pickle_dir, config_dir)
-        self._persistent_dir = pickle_dir
-        self._config_writer_cfg_dir = config_dir
-        self._config_build_templates()
-        InitdHandler.__init__(self)
-        self.host = HostHandler(self)
-        self.user = UserHandler(self)
-
-    def _get_config_vars(self, config_file):
-        if config_file == 'squid.conf':
-            return dict(hosts=self.hosts.values(), **self.params)
-        return dict(users=self.users)
-
-
-if __name__ == '__main__':
-
-    logging.basicConfig(
-        level   = logging.DEBUG,
-        format  = '%(asctime)s %(levelname)-8s %(message)s',
-        datefmt = '%H:%M:%S',
-    )
-
-    px = ProxyHandler()
-    px.set('ip','192.66.66.66')
-    px.set('port','666')
-    px.host.add('192.168.0.25.25')
-    px.host.add('192.168.0.25.26')
-    px.host.add('192.168.0.25.27')
-    px.host.delete('192.168.0.25.27')
-    px.user.add('lala','soronga')
-    px.user.add('culo','sarasa')
-    px.commit()
diff --git a/services/proxy/handler.py b/services/proxy/handler.py
new file mode 100644 (file)
index 0000000..7a52724
--- /dev/null
@@ -0,0 +1,108 @@
+# vim: set encoding=utf-8 et sw=4 sts=4 :
+
+from os import path
+import logging ; log = logging.getLogger('pymin.services.proxy')
+
+from pymin.seqtools import Sequence
+from pymin.dispatcher import Handler, handler, HandlerError
+from pymin.service.util import Restorable, ConfigWriter, InitdHandler, \
+                               TransactionalHandler, ParametersHandler, \
+                               DictSubHandler
+
+import crypt
+
+
+__all__ = ('ProxyHandler', 'get_service')
+
+
+def get_service(config):
+    return ProxyHandler(config.proxy.pickle_dir, config.proxy.config_dir)
+
+
+class Host(Sequence):
+    def __init__(self,ip):
+        self.ip = ip
+    def as_tuple(self):
+        return (self.ip,)
+
+# TODO convert to a SetSubHandler
+
+class HostHandler(DictSubHandler):
+
+    handler_help = u"Manage proxy hosts"
+
+    _cont_subhandler_attr = 'hosts'
+    _cont_subhandler_class = Host
+
+class User(Sequence):
+    def __init__(self, name, password):
+        self.name = name
+        self.password = crypt.crypt(password,'BA')
+    def as_tuple(self):
+        return (self.name, self.password)
+    def update(self, password=None):
+        if password is not None:
+            self.password = crypt.crypt(password,'BA')
+
+class UserHandler(DictSubHandler):
+
+    handler_help = u"Manage proxy users"
+
+    _cont_subhandler_attr = 'users'
+    _cont_subhandler_class = User
+
+class ProxyHandler(Restorable, ConfigWriter, InitdHandler,
+                   TransactionalHandler, ParametersHandler):
+
+    handler_help = u"Manage proxy service"
+
+    _initd_name = 'squid'
+
+    _persistent_attrs = ('params', 'hosts', 'users')
+
+    _restorable_defaults = dict(
+            hosts = dict(),
+            params  = dict(
+                ip   = '192.168.0.1',
+                port = '8080',
+            ),
+            users = dict(),
+    )
+
+    _config_writer_files = ('squid.conf','users.conf')
+    _config_writer_tpl_dir = path.join(path.dirname(__file__), 'templates')
+
+    def __init__(self, pickle_dir='.', config_dir='.'):
+        r"Initialize DhcpHandler object, see class documentation for details."
+        log.debug(u'ProxyHandler(%r, %r)', pickle_dir, config_dir)
+        self._persistent_dir = pickle_dir
+        self._config_writer_cfg_dir = config_dir
+        self._config_build_templates()
+        InitdHandler.__init__(self)
+        self.host = HostHandler(self)
+        self.user = UserHandler(self)
+
+    def _get_config_vars(self, config_file):
+        if config_file == 'squid.conf':
+            return dict(hosts=self.hosts.values(), **self.params)
+        return dict(users=self.users)
+
+
+if __name__ == '__main__':
+
+    logging.basicConfig(
+        level   = logging.DEBUG,
+        format  = '%(asctime)s %(levelname)-8s %(message)s',
+        datefmt = '%H:%M:%S',
+    )
+
+    px = ProxyHandler()
+    px.set('ip','192.66.66.66')
+    px.set('port','666')
+    px.host.add('192.168.0.25.25')
+    px.host.add('192.168.0.25.26')
+    px.host.add('192.168.0.25.27')
+    px.host.delete('192.168.0.25.27')
+    px.user.add('lala','soronga')
+    px.user.add('culo','sarasa')
+    px.commit()
index c17504951f96e88fd5070030f7c892c90df2e838..78e8134b45159adf5c78512fb4da3f7cfda2a34a 100644 (file)
@@ -1,291 +1,7 @@
 # vim: set encoding=utf-8 et sw=4 sts=4 :
 
-from subprocess import Popen, PIPE
-from os import path
-
-from pymin.seqtools import Sequence
-from pymin.dispatcher import handler, HandlerError, Handler
-from pymin.service.util import Restorable, ConfigWriter, InitdHandler, \
-                               TransactionalHandler, SubHandler, call, \
-                               get_network_devices, ListComposedSubHandler, \
-                               DictComposedSubHandler, ExecutionError
-
-__all__ = ('QoSHandler', 'get_service')
-
+from handler import QoSHandler
 
 def get_service(config):
     return QoSHandler(config.qos.pickle_dir, config.qos.config_dir)
 
-
-class DeviceError(HandlerError):
-
-    def __init__(self, dev):
-        self.message = u'Devive error : "%s"' % dev
-
-
-class DeviceNotFoundError(DeviceError):
-
-    def __init__(self, dev):
-        self.message = u'Device not found : "%s"' % dev
-
-
-class ClassError(HandlerError):
-
-    def __init__(self, cls):
-        self.message = u'Class error : "%s"' % cls
-
-
-class ClassNotFoundError(ClassError):
-
-    def __init__(self, cls):
-        self.message = u'Class not found : "%s"' % cls
-
-
-class ClassAlreadyExistsError(ClassError):
-
-    def __init__(self, cls):
-        self.message = u'Class already exists : "%s"' % cls
-
-
-class HostError(HandlerError):
-
-    def __init__(self, host):
-        self.message = u'Host error : "%s"' % host
-
-
-class HostNotFoundError(HostError):
-
-    def __init__(self, ip):
-        self.message = u'Host not found : "%s"' % host
-
-
-class HostAlreadyExistsError(HostError):
-
-    def __init__(self, ip):
-        self.message = u'Host already exists : "%s"' % host
-
-
-class Class(Sequence):
-
-    def __init__(self, cid, rate=None):
-        self.cid = cid
-        self.rate = rate
-        self.hosts = dict()
-
-    def as_tuple(self):
-        return (self.cid, self.rate)
-
-    def __cmp__(self, other):
-        if self.cid == other.cid:
-            return 0
-        return cmp(id(self), id(other))
-
-
-class ClassHandler(Handler):
-
-    def __init__(self, parent):
-        self.parent = parent
-
-    @handler('Adds a class : add <id> <device> <rate>')
-    def add(self, dev, cid, rate):
-        if not dev in self.parent.devices:
-            raise DeviceNotFoundError(dev)
-
-        try:
-            self.parent.devices[dev].classes[cid] = Class(cid, rate)
-        except ValueError:
-            raise ClassAlreadyExistsError(cid  + ' -> ' + dev)
-
-    @handler(u'Deletes a class : delete <id> <device>')
-    def delete(self, dev, cid):
-        if not dev in self.parent.devices:
-            raise DeviceNotFoundError(dev)
-
-        try:
-            del self.parent.devices[dev].classes[cid]
-        except KeyError:
-            raise ClassNotFoundError(cid + ' -> ' + dev)
-
-    @handler(u'Lists classes : list <dev>')
-    def list(self, dev):
-        try:
-            k = self.parent.devices[dev].classes.items()
-        except KeyError:
-            k = dict()
-        return k
-
-
-class Host(Sequence):
-
-    def __init__(self, ip):
-        self.ip = ip
-
-    def as_tuple(self):
-        return (self.ip)
-
-    def __cmp__(self, other):
-        if self.ip == other.ip:
-            return 0
-        return cmp(id(self), id(other))
-
-
-class HostHandler(SubHandler):
-
-    def __init__(self, parent):
-        self.parent = parent
-
-    @handler('Adds a host to a class : add <device> <class id> <ip>')
-    def add(self, dev, cid, ip):
-        if not dev in self.parent.devices:
-            raise DeviceNotFoundError(dev)
-
-        if not cid in self.parent.devices[dev].classes:
-            raise ClassNotFoundError(cid)
-
-        try:
-            self.parent.devices[dev].classes[cid].hosts[ip] = Host(ip)
-        except ValueError:
-            raise HostAlreadyExistsError(h  + ' -> ' + dev)
-
-    @handler(u'Lists hosts : list <dev> <class id>')
-    def list(self, dev, cid):
-        try:
-            k = self.parent.devices[dev].classes[cid].hosts.keys()
-        except KeyError:
-            k = dict()
-        return k
-
-
-class Device(Sequence):
-
-    def __init__(self, name, mac):
-        self.name = name
-        self.mac = mac
-        self.classes = dict()
-
-    def as_tuple(self):
-        return (self.name, self.mac)
-
-
-class DeviceHandler(SubHandler):
-
-    handler_help = u"Manage network devices"
-
-    def __init__(self, parent):
-        # FIXME remove templates to execute commands
-        from mako.template import Template
-        self.parent = parent
-        template_dir = path.join(path.dirname(__file__), 'templates')
-        dev_fn = path.join(template_dir, 'device')
-        self.device_template = Template(filename=dev_fn)
-
-    @handler(u'Bring the device up')
-    def up(self, name):
-        if name in self.parent.devices:
-            try:
-                call(self.device_template.render(dev=name, action='add'), shell=True)
-            except ExecutionError:
-                pass
-        else:
-            raise DeviceNotFoundError(name)
-
-    @handler(u'Bring the device down')
-    def down(self, name):
-        if name in self.parent.devices:
-            try:
-                call(self.device_template.render(dev=name, action='del'), shell=True)
-            except ExecutionError:
-                pass
-        else:
-            raise DeviceNotFoundError(name)
-
-    @handler(u'List all devices')
-    def list(self):
-        return self.parent.devices.keys()
-
-    @handler(u'Get information about a device')
-    def show(self):
-        return self.parent.devices.items()
-
-
-class QoSHandler(Restorable, ConfigWriter, TransactionalHandler):
-
-    handler_help = u"Manage QoS devices, classes and hosts"
-
-    _persistent_attrs = ('devices')
-
-    _restorable_defaults = dict(
-                            devices=dict((dev, Device(dev, mac))
-                                for (dev, mac) in get_network_devices().items())
-                            )
-
-    _config_writer_files = ('device', 'class_add', 'class_del', 'host_add')
-
-    _config_writer_tpl_dir = path.join(path.dirname(__file__), 'templates')
-
-    def __init__(self, pickle_dir='.', config_dir='.'):
-        r"Initialize QoSHandler object, see class documentation for details."
-        self._persistent_dir = pickle_dir
-        self._config_writer_cfg_dir = config_dir
-        self._config_build_templates()
-        self._restore()
-        self._write_config()
-        self.dev = DeviceHandler(self)
-        self.cls = ClassHandler(self)
-        self.host = HostHandler(self)
-
-    def _write_config(self):
-        r"_write_config() -> None :: Execute all commands."
-        for device in self.devices.values():
-            try:
-                call(self._render_config('device', dict(dev=device.name, action='del')), shell=True)
-            except ExecutionError:
-                pass
-
-            try:
-                call(self._render_config('device', dict(dev=device.name, action='add')), shell=True)
-            except ExecutionError:
-                pass
-
-            for cls in device.classes.values():
-                try:
-                    call(self._render_config('class_add', dict(
-                        dev = device.name,
-                        cid = cls.cid,
-                        rate = cls.rate
-                        )
-                    ), shell=True)
-                except ExecutionError:
-                    pass
-
-                for host in cls.hosts.values():
-                    try:
-                        call(self._render_config('host_add', dict(
-                            dev = device.name,
-                            ip = host.ip,
-                            cid = cls.cid
-                            )
-                        ), shell=True)
-                    except ExecutionError:
-                        pass
-
-    def handle_timer(self):
-        self.refresh_devices()
-
-    def refresh_devices(self):
-        devices = get_network_devices()
-        #add not registered devices
-        for k, v in devices.items():
-            if k not in self.devices:
-                self.devices[k] = Device(k, v)
-        #delete dead devices
-        for k in self.devices.keys():
-            if k not in devices:
-                del self.devices[k]
-
-
-if __name__ == '__main__':
-
-    qos = QoSHandler()
-    print '----------------------'
-    qos.commit()
diff --git a/services/qos/handler.py b/services/qos/handler.py
new file mode 100644 (file)
index 0000000..c175049
--- /dev/null
@@ -0,0 +1,291 @@
+# vim: set encoding=utf-8 et sw=4 sts=4 :
+
+from subprocess import Popen, PIPE
+from os import path
+
+from pymin.seqtools import Sequence
+from pymin.dispatcher import handler, HandlerError, Handler
+from pymin.service.util import Restorable, ConfigWriter, InitdHandler, \
+                               TransactionalHandler, SubHandler, call, \
+                               get_network_devices, ListComposedSubHandler, \
+                               DictComposedSubHandler, ExecutionError
+
+__all__ = ('QoSHandler', 'get_service')
+
+
+def get_service(config):
+    return QoSHandler(config.qos.pickle_dir, config.qos.config_dir)
+
+
+class DeviceError(HandlerError):
+
+    def __init__(self, dev):
+        self.message = u'Devive error : "%s"' % dev
+
+
+class DeviceNotFoundError(DeviceError):
+
+    def __init__(self, dev):
+        self.message = u'Device not found : "%s"' % dev
+
+
+class ClassError(HandlerError):
+
+    def __init__(self, cls):
+        self.message = u'Class error : "%s"' % cls
+
+
+class ClassNotFoundError(ClassError):
+
+    def __init__(self, cls):
+        self.message = u'Class not found : "%s"' % cls
+
+
+class ClassAlreadyExistsError(ClassError):
+
+    def __init__(self, cls):
+        self.message = u'Class already exists : "%s"' % cls
+
+
+class HostError(HandlerError):
+
+    def __init__(self, host):
+        self.message = u'Host error : "%s"' % host
+
+
+class HostNotFoundError(HostError):
+
+    def __init__(self, ip):
+        self.message = u'Host not found : "%s"' % host
+
+
+class HostAlreadyExistsError(HostError):
+
+    def __init__(self, ip):
+        self.message = u'Host already exists : "%s"' % host
+
+
+class Class(Sequence):
+
+    def __init__(self, cid, rate=None):
+        self.cid = cid
+        self.rate = rate
+        self.hosts = dict()
+
+    def as_tuple(self):
+        return (self.cid, self.rate)
+
+    def __cmp__(self, other):
+        if self.cid == other.cid:
+            return 0
+        return cmp(id(self), id(other))
+
+
+class ClassHandler(Handler):
+
+    def __init__(self, parent):
+        self.parent = parent
+
+    @handler('Adds a class : add <id> <device> <rate>')
+    def add(self, dev, cid, rate):
+        if not dev in self.parent.devices:
+            raise DeviceNotFoundError(dev)
+
+        try:
+            self.parent.devices[dev].classes[cid] = Class(cid, rate)
+        except ValueError:
+            raise ClassAlreadyExistsError(cid  + ' -> ' + dev)
+
+    @handler(u'Deletes a class : delete <id> <device>')
+    def delete(self, dev, cid):
+        if not dev in self.parent.devices:
+            raise DeviceNotFoundError(dev)
+
+        try:
+            del self.parent.devices[dev].classes[cid]
+        except KeyError:
+            raise ClassNotFoundError(cid + ' -> ' + dev)
+
+    @handler(u'Lists classes : list <dev>')
+    def list(self, dev):
+        try:
+            k = self.parent.devices[dev].classes.items()
+        except KeyError:
+            k = dict()
+        return k
+
+
+class Host(Sequence):
+
+    def __init__(self, ip):
+        self.ip = ip
+
+    def as_tuple(self):
+        return (self.ip)
+
+    def __cmp__(self, other):
+        if self.ip == other.ip:
+            return 0
+        return cmp(id(self), id(other))
+
+
+class HostHandler(SubHandler):
+
+    def __init__(self, parent):
+        self.parent = parent
+
+    @handler('Adds a host to a class : add <device> <class id> <ip>')
+    def add(self, dev, cid, ip):
+        if not dev in self.parent.devices:
+            raise DeviceNotFoundError(dev)
+
+        if not cid in self.parent.devices[dev].classes:
+            raise ClassNotFoundError(cid)
+
+        try:
+            self.parent.devices[dev].classes[cid].hosts[ip] = Host(ip)
+        except ValueError:
+            raise HostAlreadyExistsError(h  + ' -> ' + dev)
+
+    @handler(u'Lists hosts : list <dev> <class id>')
+    def list(self, dev, cid):
+        try:
+            k = self.parent.devices[dev].classes[cid].hosts.keys()
+        except KeyError:
+            k = dict()
+        return k
+
+
+class Device(Sequence):
+
+    def __init__(self, name, mac):
+        self.name = name
+        self.mac = mac
+        self.classes = dict()
+
+    def as_tuple(self):
+        return (self.name, self.mac)
+
+
+class DeviceHandler(SubHandler):
+
+    handler_help = u"Manage network devices"
+
+    def __init__(self, parent):
+        # FIXME remove templates to execute commands
+        from mako.template import Template
+        self.parent = parent
+        template_dir = path.join(path.dirname(__file__), 'templates')
+        dev_fn = path.join(template_dir, 'device')
+        self.device_template = Template(filename=dev_fn)
+
+    @handler(u'Bring the device up')
+    def up(self, name):
+        if name in self.parent.devices:
+            try:
+                call(self.device_template.render(dev=name, action='add'), shell=True)
+            except ExecutionError:
+                pass
+        else:
+            raise DeviceNotFoundError(name)
+
+    @handler(u'Bring the device down')
+    def down(self, name):
+        if name in self.parent.devices:
+            try:
+                call(self.device_template.render(dev=name, action='del'), shell=True)
+            except ExecutionError:
+                pass
+        else:
+            raise DeviceNotFoundError(name)
+
+    @handler(u'List all devices')
+    def list(self):
+        return self.parent.devices.keys()
+
+    @handler(u'Get information about a device')
+    def show(self):
+        return self.parent.devices.items()
+
+
+class QoSHandler(Restorable, ConfigWriter, TransactionalHandler):
+
+    handler_help = u"Manage QoS devices, classes and hosts"
+
+    _persistent_attrs = ('devices')
+
+    _restorable_defaults = dict(
+                            devices=dict((dev, Device(dev, mac))
+                                for (dev, mac) in get_network_devices().items())
+                            )
+
+    _config_writer_files = ('device', 'class_add', 'class_del', 'host_add')
+
+    _config_writer_tpl_dir = path.join(path.dirname(__file__), 'templates')
+
+    def __init__(self, pickle_dir='.', config_dir='.'):
+        r"Initialize QoSHandler object, see class documentation for details."
+        self._persistent_dir = pickle_dir
+        self._config_writer_cfg_dir = config_dir
+        self._config_build_templates()
+        self._restore()
+        self._write_config()
+        self.dev = DeviceHandler(self)
+        self.cls = ClassHandler(self)
+        self.host = HostHandler(self)
+
+    def _write_config(self):
+        r"_write_config() -> None :: Execute all commands."
+        for device in self.devices.values():
+            try:
+                call(self._render_config('device', dict(dev=device.name, action='del')), shell=True)
+            except ExecutionError:
+                pass
+
+            try:
+                call(self._render_config('device', dict(dev=device.name, action='add')), shell=True)
+            except ExecutionError:
+                pass
+
+            for cls in device.classes.values():
+                try:
+                    call(self._render_config('class_add', dict(
+                        dev = device.name,
+                        cid = cls.cid,
+                        rate = cls.rate
+                        )
+                    ), shell=True)
+                except ExecutionError:
+                    pass
+
+                for host in cls.hosts.values():
+                    try:
+                        call(self._render_config('host_add', dict(
+                            dev = device.name,
+                            ip = host.ip,
+                            cid = cls.cid
+                            )
+                        ), shell=True)
+                    except ExecutionError:
+                        pass
+
+    def handle_timer(self):
+        self.refresh_devices()
+
+    def refresh_devices(self):
+        devices = get_network_devices()
+        #add not registered devices
+        for k, v in devices.items():
+            if k not in self.devices:
+                self.devices[k] = Device(k, v)
+        #delete dead devices
+        for k in self.devices.keys():
+            if k not in devices:
+                del self.devices[k]
+
+
+if __name__ == '__main__':
+
+    qos = QoSHandler()
+    print '----------------------'
+    qos.commit()
index ebfa0ab433663dea3edc87b4a9194c11738b178f..0e2747a681d2ebde997127fa45522697aeb7b2b0 100644 (file)
@@ -1,205 +1,7 @@
 # vim: set encoding=utf-8 et sw=4 sts=4 :
 
-import os
-import errno
-import signal
-from os import path
-import logging ; log = logging.getLogger('pymin.services.vpn')
-
-
-from pymin.seqtools import Sequence
-from pymin.dispatcher import Handler, handler, HandlerError
-from pymin.service.util import Restorable, ConfigWriter, InitdHandler, \
-                               TransactionalHandler, DictSubHandler, DictComposedSubHandler, call, ExecutionError
-
-__all__ = ('VpnHandler', 'get_service')
-
+from handler import VpnHandler
 
 def get_service(config):
     return VpnHandler(config.vpn.pickle_dir, config.vpn.config_dir)
 
-
-class Host(Sequence):
-    def __init__(self, vpn_src, ip, vpn_src_net, key):
-        self.name = vpn_src
-        self.ip = ip
-        self.src_net = vpn_src_net
-        self.pub_key = key
-        self._delete = False
-
-    def as_tuple(self):
-        return(self.name, self.ip, self.src_net, self.pub_key)
-
-class HostHandler(DictComposedSubHandler):
-
-    handler_help = u"Manage hosts for a vpn"
-    _comp_subhandler_cont = 'vpns'
-    _comp_subhandler_attr = 'hosts'
-    _comp_subhandler_class = Host
-
-
-class Vpn(Sequence):
-    def __init__(self, vpn_src, vpn_dst, vpn_src_ip, vpn_src_mask,
-                    pub_key=None, priv_key=None):
-        self.vpn_src = vpn_src
-        self.vpn_dst = vpn_dst
-        self.vpn_src_ip = vpn_src_ip
-        self.vpn_src_mask = vpn_src_mask
-        self.pub_key = pub_key
-        self.priv_key = priv_key
-        self.hosts = dict()
-        self._delete = False
-
-    def as_tuple(self):
-        return(self.vpn_src, self.vpn_dst, self.vpn_src_ip, self.vpn_src_mask, self.pub_key, self.priv_key)
-
-    def update(self, vpn_dst=None, vpn_src_ip=None, vpn_src_mask=None):
-        if vpn_dst is not None:
-            self.vpn_dst = vpn_dst
-        if vpn_src_ip is not None:
-            self.vpn_src_ip = vpn_src_ip
-        if vpn_src_mask is not None:
-            self.vpn_src_mask = vpn_src_mask
-
-
-class VpnHandler(Restorable, ConfigWriter,
-                   TransactionalHandler, DictSubHandler):
-
-    handler_help = u"Manage vpn service"
-
-    _cont_subhandler_attr = 'vpns'
-    _cont_subhandler_class = Vpn
-
-    _persistent_attrs = ('vpns','hosts')
-
-    _restorable_defaults = dict(
-            vpns = dict(),
-            hosts = dict(),
-    )
-
-    _config_writer_files = ('tinc.conf','tinc-up','host')
-    _config_writer_tpl_dir = path.join(path.dirname(__file__), 'templates')
-
-    def __init__(self,  pickle_dir='.', config_dir='/etc/tinc'):
-        log.debug(u'VpnHandler(%r, %r)', pickle_dir, config_dir)
-        DictSubHandler.__init__(self, self)
-        self._config_writer_cfg_dir = config_dir
-        self._persistent_dir = pickle_dir
-        self._config_build_templates()
-        self._restore()
-        self.host = HostHandler(self)
-
-    @handler('usage: start <vpn_name>')
-    def start(self, vpn_src):
-        log.debug(u'VpnHandler.start(%r)', vpn_src)
-        if vpn_src in self.vpns:
-            call(('tincd','--net='+ vpn_src))
-
-    @handler('usage: stop <vpn_name>')
-    def stop(self, vpn_src):
-        log.debug(u'VpnHandler.stop(%r)', vpn_src)
-        if vpn_src in self.vpns:
-            pid_file = '/var/run/tinc.' + vpn_src + '.pid'
-            log.debug(u'VpnHandler.stop: getting pid from %r', pid_file)
-            if path.exists(pid_file):
-                pid = file(pid_file).readline()
-                pid = int(pid.strip())
-                try:
-                    log.debug(u'VpnHandler.stop: killing pid %r', pid)
-                    os.kill(pid, signal.SIGTERM)
-                except OSError:
-                    log.debug(u'VpnHandler.stop: error killing: %r', e)
-            else:
-                log.debug(u'VpnHandler.stop: pid file not found')
-
-    def _write_config(self):
-        log.debug(u'VpnHandler._write_config()')
-        for v in self.vpns.values():
-            log.debug(u'VpnHandler._write_config: processing %r', v)
-            #chek whether it's been created or not.
-            if not v._delete:
-                if v.pub_key is None:
-                    log.debug(u'VpnHandler._write_config: new VPN, generating '
-                                'key...')
-                    try:
-                        log.debug(u'VpnHandler._write_config: creating dir %r',
-                                    path.join(self._config_writer_cfg_dir,
-                                                v.vpn_src ,'hosts'))
-                        #first create the directory for the vpn
-                        try:
-                            os.makedirs(path.join(self._config_writer_cfg_dir,
-                                                  v.vpn_src, 'hosts'))
-                        except (IOError, OSError), e:
-                            if e.errno != errno.EEXIST:
-                                raise HandlerError(u"Can't create VPN config "
-                                                   "directory '%s' (%s)'"
-                                                    % (e.filename, e.strerror))
-                        #this command should generate 2 files inside the vpn
-                        #dir, one rsa_key.priv and one rsa_key.pub
-                        #for some reason debian does not work like this
-                        # FIXME if the < /dev/null works, is magic!
-                        log.debug(u'VpnHandler._write_config: creating key...')
-                        call(('tincd', '-n', v.vpn_src, '-K', '<', '/dev/null'))
-                        #open the created files and load the keys
-                        try:
-                            f = file(path.join(self._config_writer_cfg_dir,
-                                               v.vpn_src, 'rsa_key.pub'),
-                                     'r')
-                            pub = f.read()
-                            f.close()
-                        except (IOError, OSError), e:
-                            raise HandlerError(u"Can't read VPN key '%s' (%s)'"
-                                                % (e.filename, e.strerror))
-
-                        v.pub_key = pub
-                        v.priv_key = priv
-                    except ExecutionError, e:
-                        log.debug(u'VpnHandler._write_config: error executing '
-                                    'the command: %r', e)
-
-                vars = dict(
-                    vpn = v,
-                )
-                self._write_single_config('tinc.conf',
-                                path.join(v.vpn_src, 'tinc.conf'), vars)
-                self._write_single_config('tinc-up',
-                                path.join(v.vpn_src, 'tinc-up'), vars)
-                for h in v.hosts.values():
-                    if not h._delete:
-                        vars = dict(
-                            host = h,
-                        )
-                        self._write_single_config('host',
-                                path.join(v.vpn_src, 'hosts', h.name), vars)
-                    else:
-                        log.debug(u'VpnHandler._write_config: removing...')
-                        try:
-                            # FIXME use os.unlink()
-                            call(('rm','-f',
-                                    path.join(v.vpn_src, 'hosts', h.name)))
-                            del v.hosts[h.name]
-                        except ExecutionError, e:
-                            log.debug(u'VpnHandler._write_config: error '
-                                    'removing files: %r', e)
-            else:
-                #delete the vpn root at tinc dir
-                if path.exists('/etc/tinc/' + v.vpn_src):
-                    self.stop(v.vpn_src)
-                    call(('rm','-rf','/etc/tinc/' + v.vpn_src))
-                    del self.vpns[v.vpn_src]
-
-
-if __name__ == '__main__':
-
-    logging.basicConfig(
-        level   = logging.DEBUG,
-        format  = '%(asctime)s %(levelname)-8s %(message)s',
-        datefmt = '%H:%M:%S',
-    )
-
-    v = VpnHandler()
-    v.add('prueba','sarasa','192.168.0.188','255.255.255.0')
-    v.host.add('prueba', 'azazel' ,'192.168.0.77', '192.168.0.0',
-                'kjdhfkbdskljvkjblkbjeslkjbvkljbselvslberjhbvslbevlhb')
-    v.commit()
-
diff --git a/services/vpn/handler.py b/services/vpn/handler.py
new file mode 100644 (file)
index 0000000..ebfa0ab
--- /dev/null
@@ -0,0 +1,205 @@
+# vim: set encoding=utf-8 et sw=4 sts=4 :
+
+import os
+import errno
+import signal
+from os import path
+import logging ; log = logging.getLogger('pymin.services.vpn')
+
+
+from pymin.seqtools import Sequence
+from pymin.dispatcher import Handler, handler, HandlerError
+from pymin.service.util import Restorable, ConfigWriter, InitdHandler, \
+                               TransactionalHandler, DictSubHandler, DictComposedSubHandler, call, ExecutionError
+
+__all__ = ('VpnHandler', 'get_service')
+
+
+def get_service(config):
+    return VpnHandler(config.vpn.pickle_dir, config.vpn.config_dir)
+
+
+class Host(Sequence):
+    def __init__(self, vpn_src, ip, vpn_src_net, key):
+        self.name = vpn_src
+        self.ip = ip
+        self.src_net = vpn_src_net
+        self.pub_key = key
+        self._delete = False
+
+    def as_tuple(self):
+        return(self.name, self.ip, self.src_net, self.pub_key)
+
+class HostHandler(DictComposedSubHandler):
+
+    handler_help = u"Manage hosts for a vpn"
+    _comp_subhandler_cont = 'vpns'
+    _comp_subhandler_attr = 'hosts'
+    _comp_subhandler_class = Host
+
+
+class Vpn(Sequence):
+    def __init__(self, vpn_src, vpn_dst, vpn_src_ip, vpn_src_mask,
+                    pub_key=None, priv_key=None):
+        self.vpn_src = vpn_src
+        self.vpn_dst = vpn_dst
+        self.vpn_src_ip = vpn_src_ip
+        self.vpn_src_mask = vpn_src_mask
+        self.pub_key = pub_key
+        self.priv_key = priv_key
+        self.hosts = dict()
+        self._delete = False
+
+    def as_tuple(self):
+        return(self.vpn_src, self.vpn_dst, self.vpn_src_ip, self.vpn_src_mask, self.pub_key, self.priv_key)
+
+    def update(self, vpn_dst=None, vpn_src_ip=None, vpn_src_mask=None):
+        if vpn_dst is not None:
+            self.vpn_dst = vpn_dst
+        if vpn_src_ip is not None:
+            self.vpn_src_ip = vpn_src_ip
+        if vpn_src_mask is not None:
+            self.vpn_src_mask = vpn_src_mask
+
+
+class VpnHandler(Restorable, ConfigWriter,
+                   TransactionalHandler, DictSubHandler):
+
+    handler_help = u"Manage vpn service"
+
+    _cont_subhandler_attr = 'vpns'
+    _cont_subhandler_class = Vpn
+
+    _persistent_attrs = ('vpns','hosts')
+
+    _restorable_defaults = dict(
+            vpns = dict(),
+            hosts = dict(),
+    )
+
+    _config_writer_files = ('tinc.conf','tinc-up','host')
+    _config_writer_tpl_dir = path.join(path.dirname(__file__), 'templates')
+
+    def __init__(self,  pickle_dir='.', config_dir='/etc/tinc'):
+        log.debug(u'VpnHandler(%r, %r)', pickle_dir, config_dir)
+        DictSubHandler.__init__(self, self)
+        self._config_writer_cfg_dir = config_dir
+        self._persistent_dir = pickle_dir
+        self._config_build_templates()
+        self._restore()
+        self.host = HostHandler(self)
+
+    @handler('usage: start <vpn_name>')
+    def start(self, vpn_src):
+        log.debug(u'VpnHandler.start(%r)', vpn_src)
+        if vpn_src in self.vpns:
+            call(('tincd','--net='+ vpn_src))
+
+    @handler('usage: stop <vpn_name>')
+    def stop(self, vpn_src):
+        log.debug(u'VpnHandler.stop(%r)', vpn_src)
+        if vpn_src in self.vpns:
+            pid_file = '/var/run/tinc.' + vpn_src + '.pid'
+            log.debug(u'VpnHandler.stop: getting pid from %r', pid_file)
+            if path.exists(pid_file):
+                pid = file(pid_file).readline()
+                pid = int(pid.strip())
+                try:
+                    log.debug(u'VpnHandler.stop: killing pid %r', pid)
+                    os.kill(pid, signal.SIGTERM)
+                except OSError:
+                    log.debug(u'VpnHandler.stop: error killing: %r', e)
+            else:
+                log.debug(u'VpnHandler.stop: pid file not found')
+
+    def _write_config(self):
+        log.debug(u'VpnHandler._write_config()')
+        for v in self.vpns.values():
+            log.debug(u'VpnHandler._write_config: processing %r', v)
+            #chek whether it's been created or not.
+            if not v._delete:
+                if v.pub_key is None:
+                    log.debug(u'VpnHandler._write_config: new VPN, generating '
+                                'key...')
+                    try:
+                        log.debug(u'VpnHandler._write_config: creating dir %r',
+                                    path.join(self._config_writer_cfg_dir,
+                                                v.vpn_src ,'hosts'))
+                        #first create the directory for the vpn
+                        try:
+                            os.makedirs(path.join(self._config_writer_cfg_dir,
+                                                  v.vpn_src, 'hosts'))
+                        except (IOError, OSError), e:
+                            if e.errno != errno.EEXIST:
+                                raise HandlerError(u"Can't create VPN config "
+                                                   "directory '%s' (%s)'"
+                                                    % (e.filename, e.strerror))
+                        #this command should generate 2 files inside the vpn
+                        #dir, one rsa_key.priv and one rsa_key.pub
+                        #for some reason debian does not work like this
+                        # FIXME if the < /dev/null works, is magic!
+                        log.debug(u'VpnHandler._write_config: creating key...')
+                        call(('tincd', '-n', v.vpn_src, '-K', '<', '/dev/null'))
+                        #open the created files and load the keys
+                        try:
+                            f = file(path.join(self._config_writer_cfg_dir,
+                                               v.vpn_src, 'rsa_key.pub'),
+                                     'r')
+                            pub = f.read()
+                            f.close()
+                        except (IOError, OSError), e:
+                            raise HandlerError(u"Can't read VPN key '%s' (%s)'"
+                                                % (e.filename, e.strerror))
+
+                        v.pub_key = pub
+                        v.priv_key = priv
+                    except ExecutionError, e:
+                        log.debug(u'VpnHandler._write_config: error executing '
+                                    'the command: %r', e)
+
+                vars = dict(
+                    vpn = v,
+                )
+                self._write_single_config('tinc.conf',
+                                path.join(v.vpn_src, 'tinc.conf'), vars)
+                self._write_single_config('tinc-up',
+                                path.join(v.vpn_src, 'tinc-up'), vars)
+                for h in v.hosts.values():
+                    if not h._delete:
+                        vars = dict(
+                            host = h,
+                        )
+                        self._write_single_config('host',
+                                path.join(v.vpn_src, 'hosts', h.name), vars)
+                    else:
+                        log.debug(u'VpnHandler._write_config: removing...')
+                        try:
+                            # FIXME use os.unlink()
+                            call(('rm','-f',
+                                    path.join(v.vpn_src, 'hosts', h.name)))
+                            del v.hosts[h.name]
+                        except ExecutionError, e:
+                            log.debug(u'VpnHandler._write_config: error '
+                                    'removing files: %r', e)
+            else:
+                #delete the vpn root at tinc dir
+                if path.exists('/etc/tinc/' + v.vpn_src):
+                    self.stop(v.vpn_src)
+                    call(('rm','-rf','/etc/tinc/' + v.vpn_src))
+                    del self.vpns[v.vpn_src]
+
+
+if __name__ == '__main__':
+
+    logging.basicConfig(
+        level   = logging.DEBUG,
+        format  = '%(asctime)s %(levelname)-8s %(message)s',
+        datefmt = '%H:%M:%S',
+    )
+
+    v = VpnHandler()
+    v.add('prueba','sarasa','192.168.0.188','255.255.255.0')
+    v.host.add('prueba', 'azazel' ,'192.168.0.77', '192.168.0.0',
+                'kjdhfkbdskljvkjblkbjeslkjbvkljbselvslberjhbvslbevlhb')
+    v.commit()
+
index 5ddbbafbc8716f66387941a10d80dc07cdc44801..15cf0612a6021c06432a78cc9bddbfbb054a42fe 100644 (file)
@@ -1,81 +1,7 @@
 # vim: set encoding=utf-8 et sw=4 sts=4 :
 
-from pymin import procman
-from pymin.service.util import Restorable, TransactionalHandler, \
-                               ReloadHandler, RestartHandler, \
-                               ServiceHandler, ParametersHandler
-
-# Logger
-import logging ; log = logging.getLogger('pymin.services.vrrp')
-
-__all__ = ('VrrpHandler', 'get_service')
-
+from handler import VrrpHandler
 
 def get_service(config):
     return VrrpHandler(config.vrrp.pickle_dir, config.vrrp.config_dir)
 
-
-# FIXME the the command should not use new parameters unless commit where called
-#       i.e. integrate commit with procman to update internal procman parameters.
-class VrrpHandler(Restorable, ParametersHandler, ReloadHandler, RestartHandler,
-                        ServiceHandler, TransactionalHandler):
-
-    handler_help = u"Manage VRRP service"
-
-    _persistent_attrs = ['params']
-
-    _restorable_defaults = dict(
-        params = dict(
-                ipaddress = '192.168.0.1',
-                id        = '1',
-                prio      = '',
-                dev       = 'eth0',
-                persist   = True,
-            ),
-        )
-
-    @property
-    def _command(self):
-        command = ['vrrpd', '-i', self.params['dev'], '-v', self.params['id']]
-        if self.params['prio']:
-            command.extend(('-p', self.params['prio']))
-        command.append(self.params['ipaddress'])
-        return command
-
-    def _service_start(self):
-        log.debug(u'VrrpHandler._service_start()')
-        procinfo = procman.get('vrrp')
-        procinfo.command = self._command
-        procinfo.persist = self.params['persist']
-        procman.start('vrrp')
-
-    def _service_stop(self):
-        log.debug(u'VrrpHandler._service_stop()')
-        procman.stop('vrrp')
-
-    def _service_restart(self):
-        procinfo = procman.get('vrrp')
-        procinfo.command = self._command
-        procinfo.persist = self.params['persist']
-        procman.restart('vrrp')
-
-    def __init__(self, pickle_dir='.', config_dir='.', pid_dir='.'):
-        log.debug(u'VrrpHandler(%r, %r, %r)', pickle_dir, config_dir, pid_dir)
-        self._persistent_dir = pickle_dir
-        self._pid_dir = pid_dir
-        procman.register('vrrp', None)
-        ServiceHandler.__init__(self)
-
-
-if __name__ == '__main__':
-
-    logging.basicConfig(
-        level   = logging.DEBUG,
-        format  = '%(asctime)s %(levelname)-8s %(message)s',
-        datefmt = '%H:%M:%S',
-    )
-
-    v = VrrpHandler()
-    v.set('prio', '10')
-    v.commit()
-
diff --git a/services/vrrp/handler.py b/services/vrrp/handler.py
new file mode 100644 (file)
index 0000000..5ddbbaf
--- /dev/null
@@ -0,0 +1,81 @@
+# vim: set encoding=utf-8 et sw=4 sts=4 :
+
+from pymin import procman
+from pymin.service.util import Restorable, TransactionalHandler, \
+                               ReloadHandler, RestartHandler, \
+                               ServiceHandler, ParametersHandler
+
+# Logger
+import logging ; log = logging.getLogger('pymin.services.vrrp')
+
+__all__ = ('VrrpHandler', 'get_service')
+
+
+def get_service(config):
+    return VrrpHandler(config.vrrp.pickle_dir, config.vrrp.config_dir)
+
+
+# FIXME the the command should not use new parameters unless commit where called
+#       i.e. integrate commit with procman to update internal procman parameters.
+class VrrpHandler(Restorable, ParametersHandler, ReloadHandler, RestartHandler,
+                        ServiceHandler, TransactionalHandler):
+
+    handler_help = u"Manage VRRP service"
+
+    _persistent_attrs = ['params']
+
+    _restorable_defaults = dict(
+        params = dict(
+                ipaddress = '192.168.0.1',
+                id        = '1',
+                prio      = '',
+                dev       = 'eth0',
+                persist   = True,
+            ),
+        )
+
+    @property
+    def _command(self):
+        command = ['vrrpd', '-i', self.params['dev'], '-v', self.params['id']]
+        if self.params['prio']:
+            command.extend(('-p', self.params['prio']))
+        command.append(self.params['ipaddress'])
+        return command
+
+    def _service_start(self):
+        log.debug(u'VrrpHandler._service_start()')
+        procinfo = procman.get('vrrp')
+        procinfo.command = self._command
+        procinfo.persist = self.params['persist']
+        procman.start('vrrp')
+
+    def _service_stop(self):
+        log.debug(u'VrrpHandler._service_stop()')
+        procman.stop('vrrp')
+
+    def _service_restart(self):
+        procinfo = procman.get('vrrp')
+        procinfo.command = self._command
+        procinfo.persist = self.params['persist']
+        procman.restart('vrrp')
+
+    def __init__(self, pickle_dir='.', config_dir='.', pid_dir='.'):
+        log.debug(u'VrrpHandler(%r, %r, %r)', pickle_dir, config_dir, pid_dir)
+        self._persistent_dir = pickle_dir
+        self._pid_dir = pid_dir
+        procman.register('vrrp', None)
+        ServiceHandler.__init__(self)
+
+
+if __name__ == '__main__':
+
+    logging.basicConfig(
+        level   = logging.DEBUG,
+        format  = '%(asctime)s %(levelname)-8s %(message)s',
+        datefmt = '%H:%M:%S',
+    )
+
+    v = VrrpHandler()
+    v.set('prio', '10')
+    v.commit()
+