X-Git-Url: https://git.llucax.com/software/pymin.git/blobdiff_plain/31a4ad5fa2a20910d6faf28e3b481bcb232d3a6d..d6dfd46ed31d985e364b9ea9a404c394f15c2348:/services/ip/__init__.py?ds=sidebyside diff --git a/services/ip/__init__.py b/services/ip/__init__.py index 9152ba4..cf16088 100644 --- a/services/ip/__init__.py +++ b/services/ip/__init__.py @@ -1,42 +1,15 @@ # vim: set encoding=utf-8 et sw=4 sts=4 : -from mako.template import Template -from mako.runtime import Context from subprocess import Popen, PIPE from os import path -try: - import cPickle as pickle -except ImportError: - import pickle - -try: - from seqtools import Sequence -except ImportError: - # NOP for testing - class Sequence: pass -try: - from dispatcher import handler, HandlerError -except ImportError: - # NOP for testing - class HandlerError(RuntimeError): pass - def handler(f): return f - -__ALL__ = ('IpHandler',) - -pickle_ext = '.pkl' -pickle_devices = 'devs' - -template_dir = path.join(path.dirname(__file__), 'templates') -command_filename = 'command' - - -device_com = 'device.command' -ip_add_com = 'ip_add.command' -ip_del_com = 'ip_del.command' -ip_flush_com = 'ip_flush.command' -route_add_com = 'route_add.command' -route_del_com = 'route_del.command' -route_flush_com = 'route_flush.command' + +from seqtools import Sequence +from dispatcher import handler, HandlerError, Handler +from services.util import Restorable, ConfigWriter +from services.util import InitdHandler, TransactionalHandler + +__ALL__ = ('IpHandler','Error','DeviceError','DeviceNotFoundError','RouteError','RouteNotFoundError', + 'RouteAlreadyExistsError','AddressError','AddressNotFoundError','AddressAlreadyExistsError') class Error(HandlerError): r""" @@ -112,12 +85,12 @@ class Route(Sequence): return 0 return cmp(id(self), id(other)) -class RouteHandler: +class RouteHandler(Handler): def __init__(self, devices): self.devices = devices - @handler + @handler(u'Adds a route to a device') def add(self, device, net_addr, prefix, gateway): if not device in self.devices: raise DeviceNotFoundError(device) @@ -128,7 +101,7 @@ class RouteHandler: except ValueError: self.devices[device].routes.append(r) - @handler + @handler(u'Deletes a route from a device') def delete(self, device, net_addr, prefix, gateway): if not device in self.devices: raise DeviceNotFoundError(device) @@ -138,14 +111,14 @@ class RouteHandler: except ValueError: raise RouteNotFoundError(net_addr + '/' + prefix + '->' + gateway) - @handler + @handler(u'Flushes routes from a device') def flush(self, device): if not device in self.devices: raise DeviceNotFoundError(device) self.devices[device].routes = list() - @handler + @handler(u'List routes') def list(self, device): try: k = self.devices[device].routes.keys() @@ -153,7 +126,7 @@ class RouteHandler: k = list() return k - @handler + @handler(u'Get information about all routes') def show(self): try: k = self.devices[device].routes.values() @@ -171,12 +144,12 @@ class Address(Sequence): def as_tuple(self): return (self.ip, self.prefix, self.broadcast) -class AddressHandler: +class AddressHandler(Handler): def __init__(self, devices): self.devices = devices - @handler + @handler(u'Adds an address to a device') def add(self, device, ip, prefix, broadcast='+'): if not device in self.devices: raise DeviceNotFoundError(device) @@ -184,7 +157,7 @@ class AddressHandler: raise AddressAlreadyExistsError(ip) self.devices[device].addrs[ip] = Address(ip, prefix, broadcast) - @handler + @handler(u'Deletes an address from a device') def delete(self, device, ip): if not device in self.devices: raise DeviceNotFoundError(device) @@ -192,13 +165,13 @@ class AddressHandler: raise AddressNotFoundError(ip) del self.devices[device].addrs[ip] - @handler + @handler(u'Flushes addresses from a device') def flush(self, device): if not device in self.devices: raise DeviceNotFoundError(device) self.devices[device].addrs = dict() - @handler + @handler(u'List all addresses from a device') def list(self, device): try: k = self.devices[device].addrs.keys() @@ -206,7 +179,7 @@ class AddressHandler: k = list() return k - @handler + @handler(u'Get information about addresses from a device') def show(self, device): try: k = self.devices[device].addrs.values() @@ -225,143 +198,94 @@ class Device(Sequence): def as_tuple(self): return (self.name, self.mac) -class DeviceHandler: +class DeviceHandler(Handler): def __init__(self, devices): + # FIXME remove templates to execute commands + from mako.template import Template self.devices = devices - dev_fn = path.join(template_dir, device_com) + template_dir = path.join(path.dirname(__file__), 'templates') + dev_fn = path.join(template_dir, 'device') self.device_template = Template(filename=dev_fn) - @handler + @handler(u'Bring the device up') def up(self, name): if name in self.devices: print self.device_template.render(dev=name, action='up') else: raise DeviceNotFoundError(name) - @handler + @handler(u'Bring the device down') def down(self, name): if name in self.devices: print self.device_template.render(dev=name, action='down') else: raise DeviceNotFoundError(name) - @handler + @handler(u'List all devices') def list(self): return self.devices.keys() - @handler + @handler(u'Get information about a device') def show(self): return self.devices.items() -class IpHandler: +def get_devices(): + p = Popen(('ip', 'link', 'list'), stdout=PIPE, close_fds=True) + string = p.stdout.read() + p.wait() + d = dict() + i = string.find('eth') + while i != -1: + eth = string[i:i+4] + m = string.find('link/ether', i+4) + mac = string[ m+11 : m+11+17] + d[eth] = Device(eth, mac) + i = string.find('eth', m+11+17) + return d - def __init__(self, pickle_dir='.', config_dir='.'): - r"Initialize DhcpHandler object, see class documentation for details." +class IpHandler(Restorable, ConfigWriter, TransactionalHandler): - self.pickle_dir = pickle_dir - self.config_dir = config_dir + _persistent_vars = 'devices' - ip_add_fn = path.join(template_dir, ip_add_com) - ip_del_fn = path.join(template_dir, ip_del_com) - ip_flush_fn = path.join(template_dir, ip_flush_com) - self.ip_add_template = Template(filename=ip_add_fn) - self.ip_del_template = Template(filename=ip_del_fn) - self.ip_flush_template = Template(filename=ip_flush_fn) + _restorable_defaults = dict(devices=get_devices()) - route_add_fn = path.join(template_dir, route_add_com) - route_del_fn = path.join(template_dir, route_del_com) - route_flush_fn = path.join(template_dir, route_flush_com) - self.route_add_template = Template(filename=route_add_fn) - self.route_del_template = Template(filename=route_del_fn) - self.route_flush_template = Template(filename=route_flush_fn) + _config_writer_files = ('device', 'ip_add', 'ip_del', 'ip_flush', + 'route_add', 'route_del', 'route_flush') + _config_writer_tpl_dir = path.join(path.dirname(__file__), 'templates') - try: - self._load() - except IOError: - p = Popen('ip link list', shell=True, stdout=PIPE, close_fds=True) - devs = _get_devices(p.stdout.read()) - self.devices = dict() - for eth, mac in devs.values(): - self.devices[eth] = Device(eth, mac) - self._dump() + def __init__(self, pickle_dir='.', config_dir='.'): + r"Initialize DhcpHandler object, see class documentation for details." + self._persistent_dir = pickle_dir + self._config_writer_cfg_dir = config_dir + self._config_build_templates() + self._restore() self.addr = AddressHandler(self.devices) self.route = RouteHandler(self.devices) self.dev = DeviceHandler(self.devices) - self.commit() - - @handler - def commit(self): - r"commit() -> None :: Commit the changes and reload the DHCP service." - #esto seria para poner en una interfaz - #y seria que hace el pickle deberia llamarse - #al hacerse un commit - self._dump() - self._write_config() - - @handler - def rollback(self): - r"rollback() -> None :: Discard the changes not yet commited." - self._load() - - def _dump(self): - r"_dump() -> None :: Dump all persistent data to pickle files." - # XXX podría ir en una clase base - self._dump_var(self.devices, pickle_devices) - - - def _load(self): - r"_load() -> None :: Load all persistent data from pickle files." - # XXX podría ir en una clase base - self.devices = self._load_var(pickle_devices) - - def _pickle_filename(self, name): - r"_pickle_filename() -> string :: Construct a pickle filename." - # XXX podría ir en una clase base - return path.join(self.pickle_dir, name) + pickle_ext - - def _dump_var(self, var, name): - r"_dump_var() -> None :: Dump a especific variable to a pickle file." - # XXX podría ir en una clase base - pkl_file = file(self._pickle_filename(name), 'wb') - pickle.dump(var, pkl_file, 2) - pkl_file.close() - - def _load_var(self, name): - r"_load_var()7 -> object :: Load a especific pickle file." - # XXX podría ir en una clase base - return pickle.load(file(self._pickle_filename(name))) def _write_config(self): r"_write_config() -> None :: Execute all commands." for device in self.devices.values(): - print self.route_flush_template.render(dev=device.name) - print self.ip_flush_template.render(dev=device.name) + print self._render_config('route_flush', dict(dev=device.name)) + print self._render_config('ip_flush', dict(dev=device.name)) for address in device.addrs.values(): - print self.ip_add_template.render( - dev=device.name, - addr=address.ip, - prefix=address.prefix, - broadcast=address.broadcast + print self._render_config('ip_add', dict( + dev = device.name, + addr = address.ip, + prefix = address.prefix, + broadcast = address.broadcast, ) + ) for route in device.routes: - print self.route_add_template.render( - dev=device.name, - net_addr=route.net_addr, - prefix=route.prefix, - gateway=route.gateway + print self._render_config('route_add', dict( + dev = device.name, + net_addr = route.net_addr, + prefix = route.prefix, + gateway = route.gateway, ) + ) - def _get_devices(string): - l = list() - i = string.find('eth') - while i != -1: - eth = string[i:i+4] - m = string.find('link/ether', i+4) - mac = string[ m+11 : m+11+17] - l.append((eth,mac)) - i = string.find('eth', m+11+17) - return l if __name__ == '__main__':