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.services.util import Restorable, ConfigWriter, ReloadHandler, \
12 TransactionalHandler, DictSubHandler, call
14 __ALL__ = ('PppHandler',)
16 class ConnectionError(HandlerError, KeyError):
18 ConnectionError(hostname) -> ConnectionError instance
20 This is the base exception for all connection related errors.
23 def __init__(self, connection):
24 r"Initialize the object. See class documentation for more info."
25 self.message = u'Connection error: "%s"' % connection
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
32 class Connection(Sequence):
34 def __init__(self, name, username, password, type, **kw):
36 self.username = username
37 self.password = password
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('\\','\\\\')
50 if not 'device' in kw:
51 raise ConnectionError('Bad arguments for type=PPP')
52 self.device = kw['device']
54 raise ConnectionError('Bad arguments, unknown or unspecified type')
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)
62 def update(self, device=None, username=None, password=None):
63 if device is not None:
65 if username is not None:
66 self.username = username
67 if password is not None:
68 self.password = password
71 class ConnectionHandler(DictSubHandler):
73 handler_help = u"Manages connections for the ppp service"
75 _cont_subhandler_attr = 'conns'
76 _cont_subhandler_class = Connection
78 class PppHandler(Restorable, ConfigWriter, ReloadHandler, TransactionalHandler):
80 handler_help = u"Manage ppp service"
82 _persistent_attrs = ['conns']
84 _restorable_defaults = dict(
88 _config_writer_files = ('options.X','pap-secrets','chap-secrets','nameX')
89 _config_writer_tpl_dir = path.join(path.dirname(__file__), 'templates')
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()
98 log.debug(u'PppHandler(): restoring connections...')
99 for conn in self.conns.values():
101 log.debug(u'PppHandler(): starting connection %r', conn.name)
102 conn._running = False
103 self.start(conn.name)
104 self.conn = ConnectionHandler(self)
106 @handler(u'Start one or all the connections.')
107 def start(self, name=None):
108 log.debug(u'PppHandler.start(%r)', name)
111 names = self.conns.keys()
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')
120 log.debug(u'PppHandler.start: connection not found')
121 raise ConnectionNotFoundError(name)
123 @handler(u'Stop one or all the connections.')
124 def stop(self, name=None):
125 log.debug(u'PppHandler.stop(%r)', name)
129 names = self.conns.keys()
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())
139 log.debug(u'PppHandler.stop: killing pid %r', pid)
140 os.kill(pid, SIGTERM)
142 log.debug(u'PppHandler.stop: error killing: %r', e)
144 log.debug(u'PppHandler.stop: pid file not found')
145 self.conns[name]._running = False
146 self._dump_attr('conns')
148 log.debug(u'PppHandler.stop: connection not running')
150 log.debug(u'PppHandler.stop: connection not found')
151 raise ConnectionNotFoundError(name)
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)
158 names = self.conns.keys()
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)
169 names = self.conns.keys()
171 if self.conns[name]._running:
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)
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)
184 log.debug(u'PppHandler.running: connection not found')
185 raise ConnectionNotFoundError(name)
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')
198 log.debug(u'PppHandler.handle_timer: pid absent, NOT running')
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
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
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)
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)
225 if __name__ == '__main__':
228 level = logging.DEBUG,
229 format = '%(asctime)s %(levelname)-8s %(message)s',
230 datefmt = '%H:%M:%S',
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')