Use a plug-in architecture for services.
authorLeandro Lucarella <llucax@gmail.com>
Mon, 16 Jun 2008 18:43:45 +0000 (15:43 -0300)
committerLeandro Lucarella <llucax@gmail.com>
Mon, 16 Jun 2008 18:43:45 +0000 (15:43 -0300)
Service modules are loaded dinamically using the imp module. The config.py
file is simplified to avoid the need of defining pymind command handlers
"tree" in the configuration file.

13 files changed:
config.py
pymin/services/__init__.py
pymin/services/dhcp/__init__.py
pymin/services/dns/__init__.py
pymin/services/firewall/__init__.py
pymin/services/ip/__init__.py
pymin/services/nat/__init__.py
pymin/services/ppp/__init__.py
pymin/services/proxy/__init__.py
pymin/services/qos/__init__.py
pymin/services/vpn/__init__.py
pymin/services/vrrp/__init__.py
pymind

index aae79c1..c089eec 100644 (file)
--- a/config.py
+++ b/config.py
@@ -17,67 +17,64 @@ pickle_path = join(base_path, 'pickle')
 # FIXME, this should be specific for each service
 config_path = join(base_path, 'config')
 
-class Root(Handler):
-
-    def __init__(self):
-        try:
-            f = file("/proc/sys/net/ipv4/ip_forward","w")
-            f.write("1")
-            f.close()
-        except (IOError, OSError), e:
-            print "Can't set ip_forward:", e
-        #self.ip.device_up_hook(self.dns)
-
-    firewall = FirewallHandler(
-        pickle_dir = join(pickle_path, 'firewall'),
-        config_dir = join(config_path, 'firewall'))
-
-    nat = NatHandler(pickle_dir = join(pickle_path, 'nat'))
-
-    ppp = PppHandler(
-        pickle_dir = join(pickle_path, 'ppp'),
-        config_dir = {
-            'pap-secrets':  join(config_path, 'ppp'),
-            'chap-secrets': join(config_path, 'ppp'),
-            'options.X':    join(config_path, 'ppp'),
-            'nameX':        join(config_path, 'ppp', 'peers'),
-        })
-
-    vpn = VpnHandler(
-         pickle_dir = join(pickle_path, 'vpn'),
-         config_dir = join(config_path, 'vpn'))
-
-    ip = IpHandler(
-        pickle_dir = join(pickle_path, 'ip'),
-        config_dir = join(config_path, 'ip'))
-
-    dns = DnsHandler(
-        pickle_dir = join(pickle_path, 'dns'),
-        config_dir = {
-            'named.conf': join(config_path, 'dns'),
-            'zoneX.zone': join(config_path, 'dns', 'zones'),
-        })
-
-    dhcp = DhcpHandler(
-        pickle_dir = join(pickle_path, 'dhcp'),
-        config_dir = join(config_path, 'dhcp'))
-
-    proxy = ProxyHandler(
-        pickle_dir = join(pickle_path, 'proxy'),
-        config_dir = join(config_path, 'proxy'))
-
-    vrrp = VrrpHandler(
-        pickle_dir = join(pickle_path, 'vrrp'),
-        config_dir = join(config_path, 'vrrp'),
-        pid_dir    = join(config_path, 'vrrp', 'run'))
-
-    vpn = VpnHandler(
-        pickle_dir = join(pickle_path, 'vpn'),
-        config_dir = join(config_path, 'vpn'))
-
-    #qos = QoSHandler(
-    #    pickle_dir = join(pickle_path, 'qos'),
-    #    config_dir = join(config_path, 'qos'))
+try:
+    f = file("/proc/sys/net/ipv4/ip_forward","w")
+    f.write("1")
+    f.close()
+except (IOError, OSError), e:
+    print "Can't set ip_forward:", e
+
+class firewall:
+    pickle_dir = join(pickle_path, 'firewall')
+    config_dir = join(config_path, 'firewall')
+
+class nat:
+    pickle_dir = join(pickle_path, 'nat')
+
+class ppp:
+    pickle_dir = join(pickle_path, 'ppp')
+    config_dir = {
+        'pap-secrets':  join(config_path, 'ppp'),
+        'chap-secrets': join(config_path, 'ppp'),
+        'options.X':    join(config_path, 'ppp'),
+        'nameX':        join(config_path, 'ppp', 'peers'),
+    }
+
+class vpn:
+     pickle_dir = join(pickle_path, 'vpn')
+     config_dir = join(config_path, 'vpn')
+
+class ip:
+    pickle_dir = join(pickle_path, 'ip')
+    config_dir = join(config_path, 'ip')
+
+class dns:
+    pickle_dir = join(pickle_path, 'dns')
+    config_dir = {
+        'named.conf': join(config_path, 'dns'),
+        'zoneX.zone': join(config_path, 'dns', 'zones'),
+    }
+
+class dhcp:
+    pickle_dir = join(pickle_path, 'dhcp')
+    config_dir = join(config_path, 'dhcp')
+
+class proxy:
+    pickle_dir = join(pickle_path, 'proxy')
+    config_dir = join(config_path, 'proxy')
+
+class vrrp:
+    pickle_dir = join(pickle_path, 'vrrp')
+    config_dir = join(config_path, 'vrrp')
+    pid_dir    = join(config_path, 'vrrp', 'run')
+
+class vpn:
+    pickle_dir = join(pickle_path, 'vpn')
+    config_dir = join(config_path, 'vpn')
+
+class qos:
+    pickle_dir = join(pickle_path, 'qos')
+    config_dir = join(config_path, 'qos')
 
 bind_addr = \
 (
@@ -85,3 +82,7 @@ bind_addr = \
     9999, # Port
 )
 
+services = 'firewall nat ppp vpn ip dns dhcp proxy vrrp qos'.split()
+
+services_dirs = ['pymin/services']
+
index 7620197..1828fb4 100644 (file)
@@ -1,12 +1,19 @@
 # vim: set encoding=utf-8 et sw=4 sts=4 :
 
-from pymin.services.dhcp import DhcpHandler
-from pymin.services.dns import DnsHandler
-from pymin.services.firewall import FirewallHandler
-from pymin.services.nat import NatHandler
-from pymin.services.ip import IpHandler
-from pymin.services.proxy import ProxyHandler
-from pymin.services.vrrp import VrrpHandler
-from pymin.services.ppp import PppHandler
-from pymin.services.qos import QoSHandler
-from pymin.services.vpn import VpnHandler
+import imp
+
+class LoadError(ImportError):
+    pass
+
+def load_service(name, search_paths):
+    try:
+        (fp, path, desc) = imp.find_module(name, search_paths)
+    except ImportError:
+        raise LoadError('module "%s" not found' % name)
+
+    try:
+        return imp.load_module(name, fp, path, desc)
+    finally:
+        if fp:
+            fp.close()
+
index b5bf6f3..1c6a919 100644 (file)
@@ -9,7 +9,12 @@ from pymin.services.util import Restorable, ConfigWriter, InitdHandler, \
                                 TransactionalHandler, ParametersHandler, \
                                 DictSubHandler, ReloadHandler
 
-__all__ = ('DhcpHandler',)
+__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.
index 0576cd0..c3cf03e 100644 (file)
@@ -11,7 +11,12 @@ from pymin.services.util import Restorable, ConfigWriter, InitdHandler, \
                                 TransactionalHandler, ParametersHandler, \
                                 DictComposedSubHandler, DictSubHandler, call
 
-__all__ = ('DnsHandler',)
+__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):
index 0ab2b4c..7b17c23 100644 (file)
@@ -14,7 +14,12 @@ from pymin.dispatcher import Handler, handler, HandlerError
 from pymin.services.util import Restorable, ConfigWriter, ServiceHandler, \
                                 TransactionalHandler, ListSubHandler
 
-__all__ = ('FirewallHandler',)
+__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):
index 86551f4..54ee30b 100644 (file)
@@ -12,7 +12,11 @@ from pymin.services.util import Restorable, ConfigWriter, InitdHandler, \
                                 DictComposedSubHandler, ListSubHandler, \
                                 Device, Address, ExecutionError
 
-__all__ = ('IpHandler',)
+__all__ = ('IpHandler', 'get_service')
+
+
+def get_service(config):
+    return IpHandler(config.ip.pickle_dir, config.ip.config_dir)
 
 
 class Hop(Sequence):
index 34d5b0d..3afc997 100644 (file)
@@ -9,7 +9,12 @@ from pymin.services.util import Restorable, ConfigWriter, RestartHandler, \
                                 ReloadHandler, TransactionalHandler, \
                                 ServiceHandler, ListSubHandler, call
 
-__all__ = ('NatHandler',)
+__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.
index 6ee9f5a..7f5a143 100644 (file)
@@ -11,7 +11,12 @@ from pymin.dispatcher import Handler, handler, HandlerError
 from pymin.services.util import Restorable, ConfigWriter, ReloadHandler, \
                                 TransactionalHandler, DictSubHandler, call
 
-__all__ = ('PppHandler',)
+__all__ = ('PppHandler', 'get_service')
+
+
+def get_service(config):
+    return PppHandler(config.ppp.pickle_dir, config.ppp.config_dir)
+
 
 class ConnectionError(HandlerError, KeyError):
     r"""
index 5ab624b..448f568 100644 (file)
@@ -11,7 +11,13 @@ from pymin.services.util import Restorable, ConfigWriter, InitdHandler, \
 
 import crypt
 
-__all__ = ('ProxyHandler',)
+
+__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):
index b583d4d..d021d68 100644 (file)
@@ -10,7 +10,12 @@ from pymin.services.util import Restorable, ConfigWriter, InitdHandler, \
                                 get_network_devices, ListComposedSubHandler, \
                                 DictComposedSubHandler, ExecutionError
 
-__all__ = ('QoSHandler',)
+__all__ = ('QoSHandler', 'get_service')
+
+
+def get_service(config):
+    return QoSHandler(config.qos.pickle_dir, config.qos.config_dir)
+
 
 class DeviceError(HandlerError):
 
index f3b9f95..066e8fc 100644 (file)
@@ -13,6 +13,13 @@ from pymin.services.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
index f957bb4..9b4c0e6 100644 (file)
@@ -8,7 +8,12 @@ from pymin.services.util import Restorable, TransactionalHandler, \
 # Logger
 import logging ; log = logging.getLogger('pymin.services.vrrp')
 
-__all__ = ('VrrpHandler',)
+__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.
diff --git a/pymind b/pymind
index a04307d..2f428b5 100755 (executable)
--- a/pymind
+++ b/pymind
@@ -1,8 +1,29 @@
 #!/usr/bin/env python
 # vim: set encoding=utf-8 et sw=4 sts=4 :
 
+import sys
 from pymin.pymindaemon import PyminDaemon
+from pymin.dispatcher import Handler
+from pymin.services import load_service, LoadError
 import config
 
-PyminDaemon(config.Root(), config.bind_addr).run()
+class Root(Handler):
+    pass
+
+def build_root(config):
+    # TODO check services dependencies
+    services = dict()
+    for service in config.services:
+        try:
+            s = load_service(service, config.services_dirs)
+        except LoadError, e:
+            sys.stderr.write("Can't find service called '%s'\n" % service)
+            sys.exit(1)
+        services[service] = s
+    root = Root()
+    for name, service in services.items():
+        setattr(root, name, service.get_service(config))
+    return root
+
+PyminDaemon(build_root(config), config.bind_addr).run()