1 # vim: set encoding=utf-8 et sw=4 sts=4 :
3 from subprocess import Popen, PIPE
5 import logging ; log = logging.getLogger('pymin.services.ip')
7 from pymin.seqtools import Sequence
8 from pymin.dispatcher import handler, HandlerError, Handler
9 from pymin.services.util import Restorable, ConfigWriter, InitdHandler, \
10 TransactionalHandler, SubHandler, call, \
11 get_network_devices, ListComposedSubHandler, \
12 DictComposedSubHandler, Device, Address, \
15 __ALL__ = ('IpHandler',)
17 # TODO: convertir HopHandler a ComposedSubHandler
19 class HopError(HandlerError):
21 def __init__(self, hop):
22 self.message = u'Hop error : "%s"' % hop
24 class HopNotFoundError(HopError):
26 def __init__(self, hop):
27 self.message = u'Hop not found : "%s"' % hop
29 class HopAlreadyExistsError(HopError):
31 def __init__(self, hop):
32 self.message = u'Hop already exists : "%s"' % hop
37 def __init__(self, gateway, device):
38 self.gateway = gateway
42 return (self.gateway, self.device)
44 def __cmp__(self, other):
45 if self.gateway == other.gateway \
46 and self.device == other.device:
48 return cmp(id(self), id(other))
50 class HopHandler(Handler):
52 def __init__(self, parent):
55 @handler('Adds a hop : add <gateway> <device>')
56 def add(self, gw, dev):
57 if not dev in self.parent.devices:
58 raise DeviceNotFoundError(device)
61 self.parent.hops.index(h)
62 raise HopAlreadyExistsError(gw + '->' + dev)
64 self.parent.hops.append(h)
66 @handler(u'Deletes a hop : delete <gateway> <device>')
67 def delete(self, gw, dev):
68 if not dev in self.parent.devices:
69 raise DeviceNotFoundError(device)
72 self.parent.hops.remove(h)
74 raise HopNotFoundError(gw + '->' + dev)
76 @handler(u'Lists hops : list <dev>')
77 def list(self, device):
79 k = self.parent.hops.keys()
84 @handler(u'Get information about all hops: show <dev>')
85 def show(self, device):
87 k = self.parent.hops.values()
92 class Route(Sequence):
93 def __init__(self, net_addr, prefix, gateway):
94 self.net_addr = net_addr
96 self.gateway = gateway
97 def update(self, net_addr=None, prefix=None, gateway=None):
98 if net_addr is not None: self.net_addr = net_addr
99 if prefix is not None: self.prefix = prefix
100 if gateway is not None: self.gateway = gateway
102 return(self.net_addr, self.prefix, self.gateway)
104 class RouteHandler(ListComposedSubHandler):
105 handler_help = u"Manage IP routes"
106 _comp_subhandler_cont = 'devices'
107 _comp_subhandler_attr = 'routes'
108 _comp_subhandler_class = Route
111 class AddressHandler(DictComposedSubHandler):
112 handler_help = u"Manage IP addresses"
113 _comp_subhandler_cont = 'devices'
114 _comp_subhandler_attr = 'addrs'
115 _comp_subhandler_class = Address
118 class DeviceHandler(SubHandler):
120 handler_help = u"Manage network devices"
122 def __init__(self, parent):
123 log.debug(u'DeviceHandler(%r)', parent)
124 # FIXME remove templates to execute commands
125 from mako.template import Template
127 template_dir = path.join(path.dirname(__file__), 'templates')
128 dev_fn = path.join(template_dir, 'device')
129 self.device_template = Template(filename=dev_fn)
131 @handler(u'Bring the device up')
133 log.debug(u'DeviceHandler.up(%r)', name)
134 if name in self.parent.devices:
135 call(self.device_template.render(dev=name, action='up'), shell=True)
137 log.debug(u'DeviceHandler.up: device not found')
138 raise DeviceNotFoundError(name)
140 @handler(u'Bring the device down')
141 def down(self, name):
142 log.debug(u'DeviceHandler.down(%r)', name)
143 if name in self.parent.devices:
144 call(self.device_template.render(dev=name, action='down'), shell=True)
146 log.debug(u'DeviceHandler.up: device not found')
147 raise DeviceNotFoundError(name)
149 @handler(u'List all devices')
151 log.debug(u'DeviceHandler.list()')
152 return self.parent.devices.keys()
154 @handler(u'Get information about a device')
156 log.debug(u'DeviceHandler.show()')
157 return self.parent.devices.items()
159 class IpHandler(Restorable, ConfigWriter, TransactionalHandler):
161 handler_help = u"Manage IP devices, addresses, routes and hops"
163 _persistent_attrs = ('devices','hops')
165 _restorable_defaults = dict(
166 devices=get_network_devices(),
170 _config_writer_files = ('device', 'ip_add', 'ip_del', 'ip_flush',
171 'route_add', 'route_del', 'route_flush', 'hop')
172 _config_writer_tpl_dir = path.join(path.dirname(__file__), 'templates')
174 def __init__(self, pickle_dir='.', config_dir='.'):
175 r"Initialize DhcpHandler object, see class documentation for details."
176 log.debug(u'IpHandler(%r, %r)', pickle_dir, config_dir)
177 self._persistent_dir = pickle_dir
178 self._config_writer_cfg_dir = config_dir
179 self._config_build_templates()
182 self.addr = AddressHandler(self)
183 self.route = RouteHandler(self)
184 self.dev = DeviceHandler(self)
185 self.hop = HopHandler(self)
187 def _write_config(self):
188 r"_write_config() -> None :: Execute all commands."
189 log.debug(u'IpHandler._write_config()')
190 for device in self.devices.values():
191 log.debug(u'IpHandler._write_config: processing device %s', device)
193 log.debug(u'IpHandler._write_config: flushing routes...')
194 call(self._render_config('route_flush', dict(dev=device.name)),
196 except ExecutionError, e:
197 log.debug(u'IpHandler._write_config: error flushing -> %r', e)
199 log.debug(u'IpHandler._write_config: flushing addrs...')
200 call(self._render_config('ip_flush', dict(dev=device.name)),
202 except ExecutionError, e:
203 log.debug(u'IpHandler._write_config: error flushing -> %r', e)
204 for address in device.addrs.values():
205 broadcast = address.broadcast
206 if broadcast is None:
209 log.debug(u'IpHandler._write_config: adding %r', address)
210 call(self._render_config('ip_add', dict(
213 netmask = address.netmask,
215 broadcast = broadcast,
217 except ExecutionError, e:
218 log.debug(u'IpHandler._write_config: error adding -> %r', e)
219 for route in device.routes:
221 log.debug(u'IpHandler._write_config: adding %r', route)
222 call(self._render_config('route_add', dict(
224 net_addr = route.net_addr,
225 prefix = route.prefix,
226 gateway = route.gateway,
228 except ExecutionError, e:
229 log.debug(u'IpHandler._write_config: error adding -> %r', e)
231 log.debug(u'IpHandler._write_config: we have hops: %r', self.hops)
233 log.debug(u'IpHandler._write_config: flushing default route')
234 call('ip route del default', shell=True)
235 except ExecutionError, e:
236 log.debug(u'IpHandler._write_config: error adding -> %r', e)
238 log.debug(u'IpHandler._write_config: configuring hops')
239 call(self._render_config('hop', dict(
243 except ExecutionError, e:
244 log.debug(u'IpHandler._write_config: error adding -> %r', e)
246 def handle_timer(self):
247 log.debug(u'IpHandler.handle_timer()')
248 self.refresh_devices()
250 def refresh_devices(self):
251 log.debug(u'IpHandler.update_devices()')
252 devices = get_network_devices()
253 #add not registered devices
254 for k,v in devices.items():
255 if k not in self.devices:
256 log.debug(u'IpHandler.update_devices: adding %r', v)
259 for k in self.devices.keys():
261 log.debug(u'IpHandler.update_devices: removing %s', k)
266 if __name__ == '__main__':
269 level = logging.DEBUG,
270 format = '%(asctime)s %(levelname)-8s %(message)s',
271 datefmt = '%H:%M:%S',
275 print '----------------------'
276 ip.hop.add('201.21.32.53','eth0')
277 ip.hop.add('205.65.65.25','eth1')
280 ip.addr.add('eth0','192.168.0.23','24','192.168.255.255')
281 ip.addr.add('eth0','192.168.0.26','24')
283 ip.route.add('eth0','192.168.0.0','24','192.168.0.1')
284 ip.route.add('eth0','192.168.0.5','24','192.168.0.1')
286 ip.hop.delete('201.21.32.53','eth0')
287 ip.route.clear('eth0')