1 # vim: set encoding=utf-8 et sw=4 sts=4 :
6 from signal import SIGTERM
7 import logging ; log = logging.getLogger('pymin.services.ppp')
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
14 __all__ = ('PppHandler', 'get_service')
17 def get_service(config):
18 return PppHandler(config.ppp.pickle_dir, config.ppp.config_dir)
21 class ConnectionError(HandlerError, KeyError):
23 ConnectionError(hostname) -> ConnectionError instance
25 This is the base exception for all connection related errors.
28 def __init__(self, connection):
29 r"Initialize the object. See class documentation for more info."
30 self.message = u'Connection error: "%s"' % connection
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
37 class Connection(Sequence):
39 def __init__(self, name, username, password, type, **kw):
41 self.username = username
42 self.password = password
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('\\','\\\\')
55 if not 'device' in kw:
56 raise ConnectionError('Bad arguments for type=PPP')
57 self.device = kw['device']
59 raise ConnectionError('Bad arguments, unknown or unspecified type')
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)
67 def update(self, device=None, username=None, password=None):
68 if device is not None:
70 if username is not None:
71 self.username = username
72 if password is not None:
73 self.password = password
76 class ConnectionHandler(DictSubHandler):
78 handler_help = u"Manages connections for the ppp service"
80 _cont_subhandler_attr = 'conns'
81 _cont_subhandler_class = Connection
83 class PppHandler(Restorable, ConfigWriter, ReloadHandler, TransactionalHandler):
85 handler_help = u"Manage ppp service"
87 _persistent_attrs = ['conns']
89 _restorable_defaults = dict(
93 _config_writer_files = ('options.X','pap-secrets','chap-secrets','nameX')
94 _config_writer_tpl_dir = path.join(path.dirname(__file__), 'templates')
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()
103 log.debug(u'PppHandler(): restoring connections...')
104 for conn in self.conns.values():
106 log.debug(u'PppHandler(): starting connection %r', conn.name)
107 conn._running = False
108 self.start(conn.name)
109 self.conn = ConnectionHandler(self)
111 @handler(u'Start one or all the connections.')
112 def start(self, name=None):
113 log.debug(u'PppHandler.start(%r)', name)
116 names = self.conns.keys()
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')
125 log.debug(u'PppHandler.start: connection not found')
126 raise ConnectionNotFoundError(name)
128 @handler(u'Stop one or all the connections.')
129 def stop(self, name=None):
130 log.debug(u'PppHandler.stop(%r)', name)
134 names = self.conns.keys()
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())
144 log.debug(u'PppHandler.stop: killing pid %r', pid)
145 os.kill(pid, SIGTERM)
147 log.debug(u'PppHandler.stop: error killing: %r', e)
149 log.debug(u'PppHandler.stop: pid file not found')
150 self.conns[name]._running = False
151 self._dump_attr('conns')
153 log.debug(u'PppHandler.stop: connection not running')
155 log.debug(u'PppHandler.stop: connection not found')
156 raise ConnectionNotFoundError(name)
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)
163 names = self.conns.keys()
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)
174 names = self.conns.keys()
176 if self.conns[name]._running:
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)
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)
189 log.debug(u'PppHandler.running: connection not found')
190 raise ConnectionNotFoundError(name)
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')
203 log.debug(u'PppHandler.handle_timer: pid absent, NOT running')
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
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
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)
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)
230 if __name__ == '__main__':
233 level = logging.DEBUG,
234 format = '%(asctime)s %(levelname)-8s %(message)s',
235 datefmt = '%H:%M:%S',
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')