2 # vim: set encoding=utf-8 et sw=4 sts=4 :
4 import logging ; log = logging.getLogger('pymind')
5 # First of all, we need to setup the logging framework
6 # FIXME: this should go in a configuration file
9 format = '%(asctime)s %(name)-24s %(levelname)-8s %(message)s',
10 datefmt = '%a, %d %b %Y %H:%M:%S',
15 from formencode import Invalid, validators as V
17 from pymin.config import OptionGroup, Option, ConfigOption, ListOption
18 from pymin.config import load_config, options
19 from pymin.config import ConfigError, MissingSectionHeaderError, ParsingError
20 from pymin.dispatcher import Handler
21 from pymin.pymindaemon import PyminDaemon
22 from pymin.service import load_service, LoadError
24 # exit status (1 is reserved for command-line errors)
28 # default locations where to look for configuration files
29 # all found files will be processed, overriding the previous configuration
33 '/etc/pymin/pymin.ini',
34 os.path.expanduser('~/.pymin.ini'),
35 os.path.expanduser('~/.pymin/pymin.ini'),
38 # default locations where to look for service plug-ins
39 # search stops when a service plug-in is found
41 os.path.expanduser('~/.pymin/services'),
42 '/usr/share/pymin/services',
45 # default configuration variables
46 # these are useful variables to help the user writing the configuration file
48 'pymind-data-dir': '/var/lib/pymin',
49 'pymind-pickle-dir': '/var/lib/pymin/pickle',
50 'pymind-config-dir': '/var/lib/pymin/config',
53 # Validator to check if is a valid Python identifier
54 PythonIdentifier = V.Regex(r'^[a-zA-Z_]\w*$')
56 options.init('pymind', 'Pymin daemon global options', [
57 Option('bind_addr', V.CIDR, 'a', default='127.0.0.1', metavar='ADDR',
58 help='Bind to IP ADDR'),
59 Option('bind_port', V.Int(min=1, max=65535), 'p', default=9999,
60 metavar='PORT', help="Bind to port PORT"),
61 ListOption('services', PythonIdentifier, 's', default=[],
62 metavar='SERVICE', help="manage service SERVICE"),
63 ListOption('services_dirs', V.String, 'd', default=[],
64 metavar='DIR', help="search for services in DIR"),
65 ConfigOption('config_file', 'c', metavar='FILE',
66 help="load the configuration file FILE after the default "
67 "configuration files"),
68 ConfigOption('replace_config_file', 'C', override=True, metavar='FILE',
69 help="don't load the default configuration files, just FILE"),
73 # FIXME: move to IpHandler or someplace else
74 def activate_ip_forward():
76 f = file("/proc/sys/net/ipv4/ip_forward","w")
79 except (IOError, OSError), e:
80 log.warning("Can't set ip_forward: %s", e)
83 def get_config(paths, version, desc, add_options, defaults):
84 global config_file_paths
86 (config, args) = load_config(paths, version, desc, add_options, defaults)
87 except ConfigError, e:
89 sys.exit(EXIT_CONFIG_ERROR)
90 except MissingSectionHeaderError, e:
91 log.critical("%s:%s: missing section header near: %s", e.filename, e.lineno,
93 sys.exit(EXIT_CONFIG_ERROR)
94 except ParsingError, e:
95 for (lineno, line) in e.errors:
96 log.critical("%s:%s: invalid syntax near: %s", e.filename, lineno, line)
97 log.critical(str(e.errors))
98 sys.exit(EXIT_CONFIG_ERROR)
100 log.critical(str(e.unpack_errors()))
101 sys.exit(EXIT_CONFIG_ERROR)
103 log.critical("service '%s' not found (see option --services-dir)",
105 sys.exit(EXIT_NO_SERVICE)
106 return (config, args)
111 self.services = dict()
112 def add_config_options(self, config, args):
113 for service in config.services:
114 s = load_service(service, config.services_dirs)
115 s.setup_service(options, config)
116 self.services[service] = s
118 def build_root(config, args, services):
119 from pymin.dispatcher import Handler
122 # TODO check services dependencies
124 for name, service in services.items():
125 setattr(root, name, service.get_service(config))
130 services = Services()
131 (config, args) = get_config(config_file_paths, '%prog 0.1',
132 'Router services administration daemon',
133 services.add_config_options, config_defaults)
134 root_handler = build_root(config, args, services.services)
135 activate_ip_forward()
136 PyminDaemon(root_handler, (config.bind_addr, config.bind_port)).run()
138 if __name__ == '__main__':