1 # vim: set encoding=utf-8 et sw=4 sts=4 :
3 from subprocess import Popen, PIPE
6 from pymin.seqtools import Sequence
7 from pymin.dispatcher import handler, HandlerError, Handler
8 from pymin.services.util import Restorable, ConfigWriter, InitdHandler, \
11 __ALL__ = ('IpHandler', 'Error','DeviceError', 'DeviceNotFoundError',
12 'RouteError', 'RouteNotFoundError', 'RouteAlreadyExistsError',
13 'AddressError', 'AddressNotFoundError', 'AddressAlreadyExistsError')
15 class Error(HandlerError):
17 Error(command) -> Error instance :: Base IpHandler exception class.
19 All exceptions raised by the IpHandler inherits from this one, so you can
20 easily catch any IpHandler exception.
22 message - A descriptive error message.
25 def __init__(self, message):
26 r"Initialize the Error object. See class documentation for more info."
27 self.message = message
32 class DeviceError(Error):
34 def __init__(self, device):
35 self.message = 'Device error : "%s"' % device
37 class DeviceNotFoundError(DeviceError):
39 def __init__(self, device):
40 self.message = 'Device not found : "%s"' % device
42 class AddressError(Error):
44 def __init__(self, addr):
45 self.message = 'Address error : "%s"' % addr
47 class AddressNotFoundError(AddressError):
49 def __init__(self, address):
50 self.message = 'Address not found : "%s"' % address
52 class AddressAlreadyExistsError(AddressError):
54 def __init__(self, address):
55 self.message = 'Address already exists : "%s"' % address
57 class RouteError(Error):
59 def __init__(self, route):
60 self.message = 'Route error : "%s"' % route
62 class RouteNotFoundError(RouteError):
64 def __init__(self, route):
65 self.message = 'Route not found : "%s"' % route
67 class RouteAlreadyExistsError(RouteError):
69 def __init__(self, route):
70 self.message = 'Route already exists : "%s"' % route
73 class Route(Sequence):
75 def __init__(self, net_addr, prefix, gateway):
76 self.net_addr = net_addr
78 self.gateway = gateway
81 return(self.addr, self.prefix, self.gateway)
83 def __cmp__(self, other):
84 if self.net_addr == other.net_addr \
85 and self.prefix == other.prefix \
86 and self.gateway == other.gateway:
88 return cmp(id(self), id(other))
90 class RouteHandler(Handler):
92 def __init__(self, devices):
93 self.devices = devices
95 @handler(u'Adds a route to a device')
96 def add(self, device, net_addr, prefix, gateway):
97 if not device in self.devices:
98 raise DeviceNotFoundError(device)
99 r = Route(net_addr, prefix, gateway)
101 self.devices[device].routes.index(r)
102 raise RouteAlreadyExistsError(net_addr + '/' + prefix + '->' + gateway)
104 self.devices[device].routes.append(r)
106 @handler(u'Deletes a route from a device')
107 def delete(self, device, net_addr, prefix, gateway):
108 if not device in self.devices:
109 raise DeviceNotFoundError(device)
110 r = Route(net_addr, prefix, gateway)
112 self.devices[device].routes.remove(r)
114 raise RouteNotFoundError(net_addr + '/' + prefix + '->' + gateway)
116 @handler(u'Flushes routes from a device')
117 def flush(self, device):
118 if not device in self.devices:
119 raise DeviceNotFoundError(device)
120 self.devices[device].routes = list()
123 @handler(u'List routes')
124 def list(self, device):
126 k = self.devices[device].routes.keys()
131 @handler(u'Get information about all routes')
134 k = self.devices[device].routes.values()
140 class Address(Sequence):
142 def __init__(self, ip, prefix, broadcast):
145 self.broadcast = broadcast
148 return (self.ip, self.prefix, self.broadcast)
150 class AddressHandler(Handler):
152 def __init__(self, devices):
153 self.devices = devices
155 @handler(u'Adds an address to a device')
156 def add(self, device, ip, prefix, broadcast='+'):
157 if not device in self.devices:
158 raise DeviceNotFoundError(device)
159 if ip in self.devices[device].addrs:
160 raise AddressAlreadyExistsError(ip)
161 self.devices[device].addrs[ip] = Address(ip, prefix, broadcast)
163 @handler(u'Deletes an address from a device')
164 def delete(self, device, ip):
165 if not device in self.devices:
166 raise DeviceNotFoundError(device)
167 if not ip in self.devices[device].addrs:
168 raise AddressNotFoundError(ip)
169 del self.devices[device].addrs[ip]
171 @handler(u'Flushes addresses from a device')
172 def flush(self, device):
173 if not device in self.devices:
174 raise DeviceNotFoundError(device)
175 self.devices[device].addrs = dict()
177 @handler(u'List all addresses from a device')
178 def list(self, device):
180 k = self.devices[device].addrs.keys()
185 @handler(u'Get information about addresses from a device')
186 def show(self, device):
188 k = self.devices[device].addrs.values()
194 class Device(Sequence):
196 def __init__(self, name, mac):
203 return (self.name, self.mac)
205 class DeviceHandler(Handler):
207 def __init__(self, devices):
208 # FIXME remove templates to execute commands
209 from mako.template import Template
210 self.devices = devices
211 template_dir = path.join(path.dirname(__file__), 'templates')
212 dev_fn = path.join(template_dir, 'device')
213 self.device_template = Template(filename=dev_fn)
215 @handler(u'Bring the device up')
217 if name in self.devices:
218 print self.device_template.render(dev=name, action='up')
220 raise DeviceNotFoundError(name)
222 @handler(u'Bring the device down')
223 def down(self, name):
224 if name in self.devices:
225 print self.device_template.render(dev=name, action='down')
227 raise DeviceNotFoundError(name)
229 @handler(u'List all devices')
231 return self.devices.keys()
233 @handler(u'Get information about a device')
235 return self.devices.items()
239 p = Popen(('ip', 'link', 'list'), stdout=PIPE, close_fds=True)
240 string = p.stdout.read()
243 i = string.find('eth')
246 m = string.find('link/ether', i+4)
247 mac = string[ m+11 : m+11+17]
248 d[eth] = Device(eth, mac)
249 i = string.find('eth', m+11+17)
252 class IpHandler(Restorable, ConfigWriter, TransactionalHandler):
254 _persistent_attrs = 'devices'
256 _restorable_defaults = dict(devices=get_devices())
258 _config_writer_files = ('device', 'ip_add', 'ip_del', 'ip_flush',
259 'route_add', 'route_del', 'route_flush')
260 _config_writer_tpl_dir = path.join(path.dirname(__file__), 'templates')
262 def __init__(self, pickle_dir='.', config_dir='.'):
263 r"Initialize DhcpHandler object, see class documentation for details."
264 self._persistent_dir = pickle_dir
265 self._config_writer_cfg_dir = config_dir
266 self._config_build_templates()
268 self.addr = AddressHandler(self.devices)
269 self.route = RouteHandler(self.devices)
270 self.dev = DeviceHandler(self.devices)
272 def _write_config(self):
273 r"_write_config() -> None :: Execute all commands."
274 for device in self.devices.values():
275 print self._render_config('route_flush', dict(dev=device.name))
276 print self._render_config('ip_flush', dict(dev=device.name))
277 for address in device.addrs.values():
278 print self._render_config('ip_add', dict(
281 prefix = address.prefix,
282 broadcast = address.broadcast,
285 for route in device.routes:
286 print self._render_config('route_add', dict(
288 net_addr = route.net_addr,
289 prefix = route.prefix,
290 gateway = route.gateway,
295 if __name__ == '__main__':
298 print '----------------------'
300 ip.addr.add('eth0','192.168.0.23','24','192.168.255.255')
301 ip.addr.add('eth0','192.168.0.26','24')
303 ip.route.add('eth0','192.168.0.0','24','192.168.0.1')
304 ip.route.add('eth0','192.168.0.5','24','192.168.0.1')
306 ip.route.flush('eth0')
308 ip.addr.delete('eth0','192.168.0.23')