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