]> git.llucax.com Git - software/pymin.git/blob - services/ppp/handler.py
Split ip handler in submodules (refs #2).
[software/pymin.git] / services / ppp / handler.py
1 # vim: set encoding=utf-8 et sw=4 sts=4 :
2
3 import os
4 import subprocess
5 from os import path
6 from signal import SIGTERM
7 import logging ; log = logging.getLogger('pymin.services.ppp')
8
9 from pymin.seqtools import Sequence
10 from pymin.dispatcher import Handler, handler, HandlerError
11 from pymin.service.util import Restorable, ConfigWriter, ReloadHandler, \
12                                TransactionalHandler, DictSubHandler, call
13
14 __all__ = ('PppHandler')
15
16
17 class ConnectionError(HandlerError, KeyError):
18     r"""
19     ConnectionError(hostname) -> ConnectionError instance
20
21     This is the base exception for all connection related errors.
22     """
23
24     def __init__(self, connection):
25         r"Initialize the object. See class documentation for more info."
26         self.message = u'Connection error: "%s"' % connection
27
28 class ConnectionNotFoundError(ConnectionError):
29     def __init__(self, connection):
30         r"Initialize the object. See class documentation for more info."
31         self.message = u'Connection not found error: "%s"' % connection
32
33 class Connection(Sequence):
34
35     def __init__(self, name, username, password, type, **kw):
36         self.name = name
37         self.username = username
38         self.password = password
39         self.type = type
40         self._running = False
41         if type == 'OE':
42             if not 'device' in kw:
43                 raise ConnectionError('Bad arguments for type=OE')
44             self.device = kw['device']
45         elif type == 'TUNNEL':
46             if not 'server' in kw:
47                 raise ConnectionError('Bad arguments for type=TUNNEL')
48             self.server = kw['server']
49             self.username = self.username.replace('\\','\\\\')
50         elif type == 'PPP':
51             if not 'device' in kw:
52                 raise ConnectionError('Bad arguments for type=PPP')
53             self.device = kw['device']
54         else:
55             raise ConnectionError('Bad arguments, unknown or unspecified type')
56
57     def as_tuple(self):
58         if self.type == 'TUNNEL':
59             return (self.name, self.username, self.password, self.type, self.server)
60         elif self.type == 'PPP' or self.type == 'OE':
61             return (self.name, self.username, self.password, self.type, self.device)
62
63     def update(self, device=None, username=None, password=None):
64         if device is not None:
65             self.device = device
66         if username is not None:
67             self.username = username
68         if password is not None:
69             self.password = password
70
71
72 class ConnectionHandler(DictSubHandler):
73
74     handler_help = u"Manages connections for the ppp service"
75
76     _cont_subhandler_attr = 'conns'
77     _cont_subhandler_class = Connection
78
79 class PppHandler(Restorable, ConfigWriter, ReloadHandler, TransactionalHandler):
80
81     handler_help = u"Manage ppp service"
82
83     _persistent_attrs = ['conns']
84
85     _restorable_defaults = dict(
86         conns  = dict(),
87     )
88
89     _config_writer_files = ('options.X','pap-secrets','chap-secrets','nameX')
90     _config_writer_tpl_dir = path.join(path.dirname(__file__), 'templates')
91
92     def __init__(self, pickle_dir='.', config_dir='.'):
93         r"Initialize Ppphandler object, see class documentation for details."
94         log.debug(u'PppHandler(%r, %r)', pickle_dir, config_dir)
95         self._persistent_dir = pickle_dir
96         self._config_writer_cfg_dir = config_dir
97         self._config_build_templates()
98         self._restore()
99         log.debug(u'PppHandler(): restoring connections...')
100         for conn in self.conns.values():
101             if conn._running:
102                 log.debug(u'PppHandler(): starting connection %r', conn.name)
103                 conn._running = False
104                 self.start(conn.name)
105         self.conn = ConnectionHandler(self)
106
107     @handler(u'Start one or all the connections.')
108     def start(self, name=None):
109         log.debug(u'PppHandler.start(%r)', name)
110         names = [name]
111         if name is None:
112             names = self.conns.keys()
113         for name in names:
114             if name in self.conns:
115                 if not self.conns[name]._running:
116                     log.debug(u'PppHandler.start: starting connection %r', name)
117                     call(('pppd', 'call', name))
118                     self.conns[name]._running = True
119                     self._dump_attr('conns')
120             else:
121                 log.debug(u'PppHandler.start: connection not found')
122                 raise ConnectionNotFoundError(name)
123
124     @handler(u'Stop one or all the connections.')
125     def stop(self, name=None):
126         log.debug(u'PppHandler.stop(%r)', name)
127         names = [name]
128         names = [name]
129         if name is None:
130             names = self.conns.keys()
131         for name in names:
132             if name in self.conns:
133                 if self.conns[name]._running:
134                     pid_file = '/var/run/ppp-' + name + '.pid'
135                     log.debug(u'PppHandler.stop: getting pid from %r', pid_file)
136                     if path.exists(pid_file):
137                         pid = file(pid_file).readline()
138                         pid = int(pid.strip())
139                         try:
140                             log.debug(u'PppHandler.stop: killing pid %r', pid)
141                             os.kill(pid, SIGTERM)
142                         except OSError, e:
143                             log.debug(u'PppHandler.stop: error killing: %r', e)
144                     else:
145                         log.debug(u'PppHandler.stop: pid file not found')
146                     self.conns[name]._running = False
147                     self._dump_attr('conns')
148                 else:
149                     log.debug(u'PppHandler.stop: connection not running')
150             else:
151                 log.debug(u'PppHandler.stop: connection not found')
152                 raise ConnectionNotFoundError(name)
153
154     @handler(u'Restart one or all the connections (even disconnected ones).')
155     def restart(self, name=None):
156         log.debug(u'PppHandler.restart(%r)', name)
157         names = [name]
158         if name is None:
159             names = self.conns.keys()
160         for name in names:
161             self.stop(name)
162             self.start(name)
163
164     @handler(u'Restart only one or all the already running connections.')
165     def reload(self, name=None):
166         r"reload() -> None :: Reload the configuration of the service."
167         log.debug(u'PppHandler.reload(%r)', name)
168         names = [name]
169         if name is None:
170             names = self.conns.keys()
171         for name in names:
172             if self.conns[name]._running:
173                 self.stop(name)
174                 self.start(name)
175
176     @handler(u'Tell if the service is running.')
177     def running(self, name=None):
178         r"reload() -> None :: Reload the configuration of the service."
179         log.debug(u'PppHandler.running(%r)', name)
180         if name is None:
181             return [c.name for c in self.conns.values() if c._running]
182         if name in self.conns:
183             return int(self.conns[name]._running)
184         else:
185             log.debug(u'PppHandler.running: connection not found')
186             raise ConnectionNotFoundError(name)
187
188     def handle_timer(self):
189         log.debug(u'PppHandler.handle_timer()')
190         for c in self.conns.values():
191             log.debug(u'PppHandler.handle_timer: processing connection %r', c)
192             p = subprocess.Popen(('pgrep', '-f', 'pppd call ' + c.name),
193                                     stdout=subprocess.PIPE)
194             pid = p.communicate()[0]
195             if p.returncode == 0 and len(pid) > 0:
196                 log.debug(u'PppHandler.handle_timer: pid present, running')
197                 c._running = True
198             else:
199                 log.debug(u'PppHandler.handle_timer: pid absent, NOT running')
200                 c._running = False
201
202     def _write_config(self):
203         r"_write_config() -> None :: Generate all the configuration files."
204         log.debug(u'PppHandler._write_config()')
205         #guardo los pass que van el pap-secrets
206         vars_pap = dict()
207         for conn in self.conns.values():
208             if conn.type == 'OE' or conn.type == 'PPP':
209                 vars_pap[conn.name] = conn
210         vars = dict(conns=vars_pap)
211         self._write_single_config('pap-secrets','pap-secrets',vars)
212         #guardo los pass que van el chap-secrets
213         vars_chap = dict()
214         for conn in self.conns.values():
215             if conn.type == 'TUNNEL' :
216                 vars_chap[conn.name] = conn
217         vars = dict(conns=vars_chap)
218         self._write_single_config('chap-secrets','chap-secrets',vars)
219         #guard las conns
220         for conn in self.conns.values():
221             vars = dict(conn=conn)
222             self._write_single_config('nameX',conn.name, vars)
223             self._write_single_config('options.X','options.' + conn.name, vars)
224
225
226 if __name__ == '__main__':
227
228     logging.basicConfig(
229         level   = logging.DEBUG,
230         format  = '%(asctime)s %(levelname)-8s %(message)s',
231         datefmt = '%H:%M:%S',
232     )
233
234     p = PppHandler()
235     p.conn.add('ppp_c','nico','nico',type='PPP',device='tty0')
236     p.conn.add('pppoe_c','fede','fede',type='OE',device='tty1')
237     p.conn.add('ppptunnel_c','dominio\luca','luca',type='TUNNEL',server='192.168.0.23')
238     p.commit()
239     print p.conn.list()
240     print p.conn.show()
241