]> git.llucax.com Git - software/pymin.git/blob - pymind
Add configuration and command-line option framework.
[software/pymin.git] / pymind
1 #!/usr/bin/env python
2 # vim: set encoding=utf-8 et sw=4 sts=4 :
3
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
7 logging.basicConfig(
8         level   = logging.DEBUG,
9         format  = '%(asctime)s %(name)-24s %(levelname)-8s %(message)s',
10         datefmt = '%a, %d %b %Y %H:%M:%S',
11 )
12
13 import os
14 import sys
15 from formencode import Invalid, validators as V
16
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
23
24 # exit status (1 is reserved for command-line errors)
25 EXIT_CONFIG_ERROR = 2
26 EXIT_NO_SERVICE   = 3
27
28 # default locations where to look for configuration files
29 # all found files will be processed, overriding the previous configuration
30 # files values.
31 config_file_paths = [
32     '/etc/pymin.ini',
33     '/etc/pymin/pymin.ini',
34     os.path.expanduser('~/.pymin.ini'),
35     os.path.expanduser('~/.pymin/pymin.ini'),
36 ]
37
38 # default locations where to look for service plug-ins
39 # search stops when a service plug-in is found
40 services_paths = [
41     os.path.expanduser('~/.pymin/services'),
42     '/usr/share/pymin/services',
43 ]
44
45 # default configuration variables
46 # these are useful variables to help the user writing the configuration file
47 config_defaults = {
48     'pymind-data-dir':   '/var/lib/pymin',
49     'pymind-pickle-dir': '/var/lib/pymin/pickle',
50     'pymind-config-dir': '/var/lib/pymin/config',
51 }
52
53 # Validator to check if is a valid Python identifier
54 PythonIdentifier = V.Regex(r'^[a-zA-Z_]\w*$')
55
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"),
70 ])
71
72
73 # FIXME
74 try:
75     f = file("/proc/sys/net/ipv4/ip_forward","w")
76     f.write("1")
77     f.close()
78 except (IOError, OSError), e:
79     log.warning("Can't set ip_forward: %s", e)
80
81
82 def get_config(paths, version, desc, add_options, defaults):
83     global config_file_paths
84     try:
85         (config, args) = load_config(paths, version, desc, add_options, defaults)
86     except ConfigError, e:
87         log.error(str(e))
88         sys.exit(EXIT_CONFIG_ERROR)
89     except MissingSectionHeaderError, e:
90         log.error("%s:%s: missing section header near: %s", e.filename, e.lineno,
91                   e.line)
92         sys.exit(EXIT_CONFIG_ERROR)
93     except ParsingError, e:
94         for (lineno, line) in e.errors:
95             log.error("%s:%s: invalid syntax near: %s", e.filename, lineno, line)
96         log.error(str(e.errors))
97         sys.exit(EXIT_CONFIG_ERROR)
98     except Invalid, e:
99         log.error(str(e.unpack_errors()))
100         sys.exit(EXIT_CONFIG_ERROR)
101     except LoadError, e:
102         log.error("service '%s' not found (see option --services-dir)",
103                   e.service_name)
104         sys.exit(EXIT_NO_SERVICE)
105     return (config, args)
106
107
108 class Services:
109     def __init__(self):
110         self.services = dict()
111     def add_config_options(self, config, args):
112         for service in config.services:
113             s = load_service(service, config.services_dirs)
114             s.setup_service(options, config)
115             self.services[service] = s
116
117 def build_root(config, args, services):
118     from pymin.dispatcher import Handler
119     class Root(Handler):
120         pass
121     # TODO check services dependencies
122     root = Root()
123     for name, service in services.items():
124         setattr(root, name, service.get_service(config))
125     return root
126
127
128 def main():
129     services = Services()
130     (config, args) = get_config(config_file_paths, '%prog 0.1',
131                                 'Router services administration daemon',
132                                 services.add_config_options, config_defaults)
133     root_handler = build_root(config, args, services.services)
134     PyminDaemon(root_handler, (config.bind_addr, config.bind_port)).run()
135
136 if __name__ == '__main__':
137     main()
138