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')
17 class ConnectionError(HandlerError, KeyError):
19 ConnectionError(hostname) -> ConnectionError instance
21 This is the base exception for all connection related errors.
24 def __init__(self, connection):
25 r"Initialize the object. See class documentation for more info."
26 self.message = u'Connection error: "%s"' % connection
28 class ConnectionNotFoundError(ConnectionError):
29 def __init__(self, connection):
30 r"Initialize the object. See class documentation for more info."
31 self.message = u'Connection not found error: "%s"' % connection
33 class Connection(Sequence):
35 def __init__(self, name, username, password, type, **kw):
37 self.username = username
38 self.password = password
42 if not 'device' in kw:
43 raise ConnectionError('Bad arguments for type=OE')
44 self.device = kw['device']
45 elif type == 'TUNNEL':
46 if not 'server' in kw:
47 raise ConnectionError('Bad arguments for type=TUNNEL')
48 self.server = kw['server']
49 self.username = self.username.replace('\\','\\\\')
51 if not 'device' in kw:
52 raise ConnectionError('Bad arguments for type=PPP')
53 self.device = kw['device']
55 raise ConnectionError('Bad arguments, unknown or unspecified type')
58 if self.type == 'TUNNEL':
59 return (self.name, self.username, self.password, self.type, self.server)
60 elif self.type == 'PPP' or self.type == 'OE':
61 return (self.name, self.username, self.password, self.type, self.device)
63 def update(self, device=None, username=None, password=None):
64 if device is not None:
66 if username is not None:
67 self.username = username
68 if password is not None:
69 self.password = password
72 class ConnectionHandler(DictSubHandler):
74 handler_help = u"Manages connections for the ppp service"
76 _cont_subhandler_attr = 'conns'
77 _cont_subhandler_class = Connection
79 class PppHandler(Restorable, ConfigWriter, ReloadHandler, TransactionalHandler):
81 handler_help = u"Manage ppp service"
83 _persistent_attrs = ['conns']
85 _restorable_defaults = dict(
89 _config_writer_files = ('options.X','pap-secrets','chap-secrets','nameX')
90 _config_writer_tpl_dir = path.join(path.dirname(__file__), 'templates')
92 def __init__(self, pickle_dir='.', config_dir='.'):
93 r"Initialize Ppphandler object, see class documentation for details."
94 log.debug(u'PppHandler(%r, %r)', pickle_dir, config_dir)
95 self._persistent_dir = pickle_dir
96 self._config_writer_cfg_dir = config_dir
97 self._config_build_templates()
99 log.debug(u'PppHandler(): restoring connections...')
100 for conn in self.conns.values():
102 log.debug(u'PppHandler(): starting connection %r', conn.name)
103 conn._running = False
104 self.start(conn.name)
105 self.conn = ConnectionHandler(self)
107 @handler(u'Start one or all the connections.')
108 def start(self, name=None):
109 log.debug(u'PppHandler.start(%r)', name)
112 names = self.conns.keys()
114 if name in self.conns:
115 if not self.conns[name]._running:
116 log.debug(u'PppHandler.start: starting connection %r', name)
117 call(('pppd', 'call', name))
118 self.conns[name]._running = True
119 self._dump_attr('conns')
121 log.debug(u'PppHandler.start: connection not found')
122 raise ConnectionNotFoundError(name)
124 @handler(u'Stop one or all the connections.')
125 def stop(self, name=None):
126 log.debug(u'PppHandler.stop(%r)', name)
130 names = self.conns.keys()
132 if name in self.conns:
133 if self.conns[name]._running:
134 pid_file = '/var/run/ppp-' + name + '.pid'
135 log.debug(u'PppHandler.stop: getting pid from %r', pid_file)
136 if path.exists(pid_file):
137 pid = file(pid_file).readline()
138 pid = int(pid.strip())
140 log.debug(u'PppHandler.stop: killing pid %r', pid)
141 os.kill(pid, SIGTERM)
143 log.debug(u'PppHandler.stop: error killing: %r', e)
145 log.debug(u'PppHandler.stop: pid file not found')
146 self.conns[name]._running = False
147 self._dump_attr('conns')
149 log.debug(u'PppHandler.stop: connection not running')
151 log.debug(u'PppHandler.stop: connection not found')
152 raise ConnectionNotFoundError(name)
154 @handler(u'Restart one or all the connections (even disconnected ones).')
155 def restart(self, name=None):
156 log.debug(u'PppHandler.restart(%r)', name)
159 names = self.conns.keys()
164 @handler(u'Restart only one or all the already running connections.')
165 def reload(self, name=None):
166 r"reload() -> None :: Reload the configuration of the service."
167 log.debug(u'PppHandler.reload(%r)', name)
170 names = self.conns.keys()
172 if self.conns[name]._running:
176 @handler(u'Tell if the service is running.')
177 def running(self, name=None):
178 r"reload() -> None :: Reload the configuration of the service."
179 log.debug(u'PppHandler.running(%r)', name)
181 return [c.name for c in self.conns.values() if c._running]
182 if name in self.conns:
183 return int(self.conns[name]._running)
185 log.debug(u'PppHandler.running: connection not found')
186 raise ConnectionNotFoundError(name)
188 def handle_timer(self):
189 log.debug(u'PppHandler.handle_timer()')
190 for c in self.conns.values():
191 log.debug(u'PppHandler.handle_timer: processing connection %r', c)
192 p = subprocess.Popen(('pgrep', '-f', 'pppd call ' + c.name),
193 stdout=subprocess.PIPE)
194 pid = p.communicate()[0]
195 if p.returncode == 0 and len(pid) > 0:
196 log.debug(u'PppHandler.handle_timer: pid present, running')
199 log.debug(u'PppHandler.handle_timer: pid absent, NOT running')
202 def _write_config(self):
203 r"_write_config() -> None :: Generate all the configuration files."
204 log.debug(u'PppHandler._write_config()')
205 #guardo los pass que van el pap-secrets
207 for conn in self.conns.values():
208 if conn.type == 'OE' or conn.type == 'PPP':
209 vars_pap[conn.name] = conn
210 vars = dict(conns=vars_pap)
211 self._write_single_config('pap-secrets','pap-secrets',vars)
212 #guardo los pass que van el chap-secrets
214 for conn in self.conns.values():
215 if conn.type == 'TUNNEL' :
216 vars_chap[conn.name] = conn
217 vars = dict(conns=vars_chap)
218 self._write_single_config('chap-secrets','chap-secrets',vars)
220 for conn in self.conns.values():
221 vars = dict(conn=conn)
222 self._write_single_config('nameX',conn.name, vars)
223 self._write_single_config('options.X','options.' + conn.name, vars)
226 if __name__ == '__main__':
229 level = logging.DEBUG,
230 format = '%(asctime)s %(levelname)-8s %(message)s',
231 datefmt = '%H:%M:%S',
235 p.conn.add('ppp_c','nico','nico',type='PPP',device='tty0')
236 p.conn.add('pppoe_c','fede','fede',type='OE',device='tty1')
237 p.conn.add('ppptunnel_c','dominio\luca','luca',type='TUNNEL',server='192.168.0.23')