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