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