* Paths.
* SubHandlers:
- * ComposeDictSubHandler con soporte de dirty/del/add (para ip y DNS).
- * Agregar SimpleDictSubHandler? (que no use una clase, que use un dict
- de strings directamente, para Proxy Users por ej.). Ídem List.
* Agregar SetSubHandler? (para Proxy Hosts)
* Agregar logging.
* Agregar validación con formencode.
-* Ver como manejar la información sobre si un servicio está andando o no. Si se
- agrega una acción 'status' para ver el estado y si ese estado se saca de posta
- de /proc o si es un estado interno y se asume que los servicios no se caen (no
- creo que sea una buena idea esto último). Además habría que ver cuando arranca
- el pymin, si se inician servicios automáticamente o no y si la info de qué
- servicios iniciar o no es persistente y si puede configurarla el usuario.
+* Hacer que el estado sobre si un servicio está andando o no sea más confiable
+ que un simple flag interno (en caso de ver que realmente esté corriendo,
+ probablemente sea una buena idea que haya un flag que indique si hay que
+ levantarlo en el inicio).
* No usar comandos con templates, porque después si no hay que ejecutarlos con
un shell (porque el template devuelve un string todo grande) y hay que andar
teniendo cuidado de escapar las cosas (y hay riesgos de seguridad de shell
injection).
-Estas cosas quedan sujetas a necesitada y a definición del protocolo.
-Para mí lo ideal es que el protocolo de red sea igual que la consola del
-usuario, porque después de todo no va a ser más que eso, mandar comanditos.
-
-Por otro lado, el cliente de consola, por que no es el cliente web pero
-accedido via ssh usando un navegador de texto como w3m???
-
self._persistent_dir = pickle_dir
self._config_writer_cfg_dir = config_dir
self._config_build_templates()
- self._restore()
+ InitdHandler.__init__(self)
self.host = HostHandler(self)
def _get_config_vars(self, config_file):
self._config_writer_cfg_dir = config_dir
self._update = False
self._config_build_templates()
- self._restore()
- # FIXME self._update = True
- #if not self._restore():
- #r = self._restore()
- #print r
- #if not r:
- # self._update = True
+ InitdHandler.__init__(self)
self.host = HostHandler(self)
self.zone = ZoneHandler(self)
self.mx = MailExchangeHandler(self)
delete_zones = list()
for a_zone in self.zones.values():
if a_zone._update or a_zone._add:
- if not a_zone._add:
+ if not a_zone._add and self._service_running:
call(('rndc', 'freeze', a_zone.name))
vars = dict(
zone = a_zone,
self._write_single_config('zoneX.zone',
self._zone_filename(a_zone), vars)
a_zone._update = False
- if not a_zone._add:
+ if not a_zone._add and self._service_running:
call(('rndc', 'thaw', a_zone.name))
else :
self._update = True
if self._update:
self._write_single_config('named.conf')
self._update = False
- self.reload()
+ return False # Do reload
+ return True # we don't need to reload
if __name__ == '__main__':
handler_help = u"Manage firewall service"
- _persistent_attrs = 'rules'
+ _persistent_attrs = ['rules']
_restorable_defaults = dict(rules=list())
self._service_restart = self._service_start
self._service_reload = self._service_start
self._config_build_templates()
- self._restore()
+ ServiceHandler.__init__(self)
self.rule = RuleHandler(self)
def _get_config_vars(self, config_file):
self._config_writer_cfg_dir = config_dir
self._config_build_templates()
self._restore()
+ self._write_config()
self.addr = AddressHandler(self)
self.route = RouteHandler(self)
self.dev = DeviceHandler(self)
from pymin.dispatcher import Handler, handler, HandlerError
from pymin.services.util import Restorable, ConfigWriter, RestartHandler, \
ReloadHandler, TransactionalHandler, \
- ListSubHandler, call
+ ServiceHandler, ListSubHandler, call
__ALL__ = ('NatHandler',)
_cont_subhandler_attr = 'masqs'
_cont_subhandler_class = Masq
-class NatHandler(Restorable, ConfigWriter, RestartHandler, ReloadHandler,
- TransactionalHandler):
+class NatHandler(Restorable, ConfigWriter, ReloadHandler, ServiceHandler,
+ TransactionalHandler):
r"""NatHandler([pickle_dir[, config_dir]]) -> NatHandler instance.
Handles NAT commands using iptables.
masqs=list(),
)
- @handler(u'Start the service.')
- def start(self):
+ def _service_start(self):
+ call(('iptables', '-t', 'nat', '-F'))
for (index, port) in enumerate(self.ports):
call(['iptables'] + port.as_call_list(index+1))
for (index, snat) in enumerate(self.snats):
for (index, masq) in enumerate(self.masqs):
call(['iptables'] + masq.as_call_list(index+1))
- @handler(u'Stop the service.')
- def stop(self):
+ def _service_stop(self):
call(('iptables', '-t', 'nat', '-F'))
+ _service_restart = _service_start
+
def __init__(self, pickle_dir='.'):
r"Initialize the object, see class documentation for details."
self._persistent_dir = pickle_dir
- self._restore()
+ ServiceHandler.__init__(self)
self.forward = PortForwardHandler(self)
self.snat = SNatHandler(self)
self.masq = MasqHandler(self)
# vim: set encoding=utf-8 et sw=4 sts=4 :
+import os
from os import path
+from signal import SIGTERM
from pymin.seqtools import Sequence
from pymin.dispatcher import Handler, handler, HandlerError
-from pymin.services.util import Restorable, ConfigWriter \
- ,TransactionalHandler, DictSubHandler, call
+from pymin.services.util import Restorable, ConfigWriter, ReloadHandler, \
+ TransactionalHandler, DictSubHandler, call
__ALL__ = ('PppHandler',)
self.username = username
self.password = password
self.type = type
+ self._running = False
if type == 'OE':
if not 'device' in kw:
raise ConnectionError('Bad arguments for type=OE')
_cont_subhandler_attr = 'conns'
_cont_subhandler_class = Connection
-class PppHandler(Restorable, ConfigWriter, TransactionalHandler):
+class PppHandler(Restorable, ConfigWriter, ReloadHandler, TransactionalHandler):
handler_help = u"Manage ppp service"
- _persistent_attrs = ('conns')
+ _persistent_attrs = ['conns']
_restorable_defaults = dict(
conns = dict(),
self._config_writer_cfg_dir = config_dir
self._config_build_templates()
self._restore()
+ for conn in self.conns.values():
+ if conn._running:
+ conn._running = False
+ self.start(conn.name)
self.conn = ConnectionHandler(self)
- @handler('Starts the service')
- def start(self, name):
- if name in self.conns:
- call(['pppd','call', name],stdout=None, stderr=None)
- #print ('pon', name)
- else:
- raise ConnectionNotFoundError(name)
-
- @handler('Stops the service')
- def stop(self, name):
+ @handler(u'Start one or all the connections.')
+ def start(self, name=None):
+ names = [name]
+ if name is None:
+ names = self.conns.keys()
+ for name in names:
+ if name in self.conns:
+ if not self.conns[name]._running:
+ call(('pppd', 'call', name))
+ self.conns[name]._running = True
+ self._dump_attr('conns')
+ else:
+ raise ConnectionNotFoundError(name)
+
+ @handler(u'Stop one or all the connections.')
+ def stop(self, name=None):
+ names = [name]
+ if name is None:
+ names = self.conns.keys()
+ for name in names:
+ if name in self.conns:
+ if self.conns[name]._running:
+ call(('poff', name))
+ if path.exists('/var/run/ppp-' + name + '.pid'):
+ pid = file('/var/run/ppp-' + name + '.pid').readline()
+ try:
+ os.kill(int(pid.strip()), SIGTERM)
+ except OSError:
+ pass # XXX report error?
+ self.conns[name]._running = False
+ self._dump_attr('conns')
+ else:
+ raise ConnectionNotFoundError(name)
+
+ @handler(u'Restart one or all the connections (even disconnected ones).')
+ def restart(self, name=None):
+ names = [name]
+ if name is None:
+ names = self.conns.keys()
+ for name in names:
+ self.stop(name)
+ self.start(name)
+
+ @handler(u'Restart only one or all the already running connections.')
+ def reload(self, name=None):
+ r"reload() -> None :: Reload the configuration of the service."
+ names = [name]
+ if name is None:
+ names = self.conns.keys()
+ for name in names:
+ if self.conns[name]._running:
+ self.stop(name)
+ self.start(name)
+
+ @handler(u'Tell if the service is running.')
+ def running(self, name=None):
+ r"reload() -> None :: Reload the configuration of the service."
+ if name is None:
+ return [c.name for c in self.conns.values() if c._running]
if name in self.conns:
- if path.exists('/var/run/ppp-' + name + '.pid'):
- pid = file('/var/run/ppp-' + name + '.pid').readline().strip()
- call(['kill',pid],stdout=None, stderr=None)
- #print ('poff', name)
+ return int(self.conns[name]._running)
else:
raise ConnectionNotFoundError(name)
- @handler('Reloads the service')
- def reload(self):
- for conn in self.conns.values():
- self.stop(conn.name)
- self.start(conn.name)
-
def _write_config(self):
r"_write_config() -> None :: Generate all the configuration files."
#guardo los pass que van el pap-secrets
p.commit()
print p.conn.list()
print p.conn.show()
+
self._persistent_dir = pickle_dir
self._config_writer_cfg_dir = config_dir
self._config_build_templates()
- self._restore()
+ InitdHandler.__init__(self)
self.host = HostHandler(self)
self.user = UserHandler(self)
r"_restore() -> bool :: Restore persistent data or create a default."
try:
self._load()
- # TODO tener en cuenta servicios que hay que levantar y los que no
- if hasattr(self, 'commit'): # TODO deberia ser reload y/o algo para comandos
- self.commit()
return True
except IOError:
for (k, v) in self._restorable_defaults.items():
self._dump()
if hasattr(self, '_write_config'):
self._write_config()
- if hasattr(self, 'reload'):
- self.reload()
return False
class ConfigWriter:
self._write_single_config(t)
-class ServiceHandler(Handler):
+class ServiceHandler(Handler, Restorable):
r"""ServiceHandler([start[, stop[, restart[, reload]]]]) -> ServiceHandler.
This is a helper class to inherit from to automatically handle services
reload=reload).items():
if action is not None:
setattr(self, '_service_%s' % name, action)
+ self._persistent_attrs = list(self._persistent_attrs)
+ self._persistent_attrs.append('_service_running')
+ if '_service_running' not in self._restorable_defaults:
+ self._restorable_defaults['_service_running'] = False
+ self._restore()
+ if self._service_running:
+ self._service_running = False
+ self.start()
@handler(u'Start the service.')
def start(self):
r"start() -> None :: Start the service."
- call(self._service_start)
+ if not self._service_running:
+ if callable(self._service_start):
+ self._service_start()
+ else:
+ call(self._service_start)
+ self._service_running = True
+ self._dump_attr('_service_running')
@handler(u'Stop the service.')
def stop(self):
r"stop() -> None :: Stop the service."
- call(self._service_stop)
+ if self._service_running:
+ if callable(self._service_stop):
+ self._service_stop()
+ else:
+ call(self._service_stop)
+ self._service_running = False
+ self._dump_attr('_service_running')
@handler(u'Restart the service.')
def restart(self):
r"restart() -> None :: Restart the service."
- call(self._service_restart)
+ if callable(self._service_restart):
+ self._service_restart()
+ else:
+ call(self._service_restart)
+ self._service_running = True
+ self._dump_attr('_service_running')
@handler(u'Reload the service config (without restarting, if possible).')
def reload(self):
r"reload() -> None :: Reload the configuration of the service."
- call(self._service_reload)
+ if self._service_running:
+ if callable(self._service_reload):
+ self._service_reload()
+ else:
+ call(self._service_reload)
+
+ @handler(u'Tell if the service is running.')
+ def running(self):
+ r"reload() -> None :: Reload the configuration of the service."
+ if self._service_running:
+ return 1
+ else:
+ return 0
class RestartHandler(Handler):
r"""RestartHandler() -> RestartHandler :: Provides generic restart command.
@handler(u'Reload the service config (alias to restart).')
def reload(self):
r"reload() -> None :: Reload the configuration of the service."
- self.restart()
+ if hasattr(self, '_service_running') and self._service_running:
+ self.restart()
-class InitdHandler(Handler):
+class InitdHandler(ServiceHandler):
+ # TODO update docs, declarative style is depracated
r"""InitdHandler([initd_name[, initd_dir]]) -> InitdHandler.
This is a helper class to inherit from to automatically handle services
self._initd_name = initd_name
if initd_dir is not None:
self._initd_dir = initd_dir
-
- @handler(u'Start the service.')
- def start(self):
- r"start() -> None :: Start the service."
- call((path.join(self._initd_dir, self._initd_name), 'start'))
-
- @handler(u'Stop the service.')
- def stop(self):
- r"stop() -> None :: Stop the service."
- call((path.join(self._initd_dir, self._initd_name), 'stop'))
-
- @handler(u'Restart the service.')
- def restart(self):
- r"restart() -> None :: Restart the service."
- call((path.join(self._initd_dir, self._initd_name), 'restart'))
-
- @handler(u'Reload the service config (without restarting, if possible).')
- def reload(self):
- r"reload() -> None :: Reload the configuration of the service."
- call((path.join(self._initd_dir, self._initd_name), 'reload'))
+ actions = dict()
+ for action in ('start', 'stop', 'restart', 'reload'):
+ actions[action] = (path.join(self._initd_dir, self._initd_name),
+ action)
+ ServiceHandler.__init__(self, **actions)
class TransactionalHandler(Handler):
r"""Handle command transactions providing a commit and rollback commands.
r"commit() -> None :: Commit the changes and reload the service."
if hasattr(self, '_dump'):
self._dump()
+ unchanged = False
if hasattr(self, '_write_config'):
- self._write_config()
- if hasattr(self, 'reload'):
+ unchanged = self._write_config()
+ if not unchanged and hasattr(self, 'reload'):
self.reload()
@handler(u'Discard all the uncommited changes.')
if not param in self.params:
raise ParameterNotFoundError(param)
self.params[param] = value
+ if hasattr(self, '_update'):
+ self._update = True
@handler(u'Get a service parameter.')
def get(self, param):
# vim: set encoding=utf-8 et sw=4 sts=4 :
+import os
from os import path
+from signal import SIGTERM
from subprocess import Popen, PIPE
from pymin.seqtools import Sequence
from pymin.dispatcher import Handler, handler, HandlerError
-from pymin.services.util import Restorable, TransactionalHandler, ParametersHandler, call
+from pymin.services.util import Restorable, TransactionalHandler, \
+ ReloadHandler, RestartHandler, \
+ ServiceHandler, ParametersHandler, call
__ALL__ = ('VrrpHandler',)
-class VrrpHandler(Restorable, ParametersHandler, TransactionalHandler):
+class VrrpHandler(Restorable, ParametersHandler, ReloadHandler, RestartHandler,
+ ServiceHandler, TransactionalHandler):
+
handler_help = u"Manage VRRP service"
- _persistent_attrs = 'params'
+ _persistent_attrs = ['params']
_restorable_defaults = dict(
params = dict( ipaddress='192.168.0.1',
),
)
- def __init__(self, pickle_dir='.', config_dir='.', pid_dir='.'):
- self._persistent_dir = pickle_dir
- self._pid_dir = pid_dir
- self._restore()
-
- @handler('Starts the service')
- def start(self):
+ def _service_start(self):
if self.params['prio'] != '':
- call(('/usr/local/bin/vrrpd','-i',self.params['dev'],'-v',self.params['id'],'-p',self.params['prio'],self.params['ipaddress']))
- #print ('vrrpd','-i',self.params['dev'],'-v',self.params['id'],'-p',self.params['prio'],self.params['ipaddress'])
+ call(('vrrp', '-i', self.params['dev'], '-v', self.params['id'],
+ '-p', self.params['prio'], self.params['ipaddress']))
else:
- call(('/usr/local/bin/vrrpd','-i',self.params['dev'],'-v',self.params['id'],self.params['ipaddress']))
- #print ('vrrpd','-i',self.params['dev'],'-v',self.params['id'],self.params['ipaddress'])
-
- @handler('Stop the service')
- def stop(self):
- try :
- pid = 'vrrpd' + '_' + self.params['dev'] + '_' + self.params['id'] + '.pid'
- f = file(path.join(self._pid_dir, pid ), 'r')
- call(('kill',f.read().strip('\n')))
- #print('kill','<',f.read())
- except IOError:
+ call(('vrrp', '-i', self.params['dev'], '-v', self.params['id'], \
+ self.params['ipaddress']))
+
+ def _service_stop(self):
+ try:
+ pid_filename = 'vrrpd_%(dev)s_%(id)s.pid' % self.params
+ pid = file(path.join(self._pid_dir, pid_filename )).read().strip()
+ os.kill(int(pid), SIGTERM)
+ except (IOError, OSError):
+ # TODO log
pass
- @handler('Reloads the service')
- def reload(self):
- self.stop()
- self.start()
+ def __init__(self, pickle_dir='.', config_dir='.', pid_dir='.'):
+ self._persistent_dir = pickle_dir
+ self._pid_dir = pid_dir
+ ServiceHandler.__init__(self)
if __name__ == '__main__':
v = VrrpHandler()
v.set('prio','10')
v.commit()
+