1 # vim: set encoding=utf-8 et sw=4 sts=4 :
3 from subprocess import Popen, PIPE
6 from seqtools import Sequence
7 from dispatcher import handler, HandlerError, Handler
8 from services.util import Restorable, ConfigWriter
9 from services.util import InitdHandler, TransactionalHandler
11 __ALL__ = ('IpHandler','Error','DeviceError','DeviceNotFoundError','RouteError','RouteNotFoundError',
12 'RouteAlreadyExistsError','AddressError','AddressNotFoundError','AddressAlreadyExistsError')
14 class Error(HandlerError):
16 Error(command) -> Error instance :: Base IpHandler exception class.
18 All exceptions raised by the IpHandler inherits from this one, so you can
19 easily catch any IpHandler exception.
21 message - A descriptive error message.
24 def __init__(self, message):
25 r"Initialize the Error object. See class documentation for more info."
26 self.message = message
31 class DeviceError(Error):
33 def __init__(self, device):
34 self.message = 'Device error : "%s"' % device
36 class DeviceNotFoundError(DeviceError):
38 def __init__(self, device):
39 self.message = 'Device not found : "%s"' % device
41 class AddressError(Error):
43 def __init__(self, addr):
44 self.message = 'Address error : "%s"' % addr
46 class AddressNotFoundError(AddressError):
48 def __init__(self, address):
49 self.message = 'Address not found : "%s"' % address
51 class AddressAlreadyExistsError(AddressError):
53 def __init__(self, address):
54 self.message = 'Address already exists : "%s"' % address
56 class RouteError(Error):
58 def __init__(self, route):
59 self.message = 'Route error : "%s"' % route
61 class RouteNotFoundError(RouteError):
63 def __init__(self, route):
64 self.message = 'Route not found : "%s"' % route
66 class RouteAlreadyExistsError(RouteError):
68 def __init__(self, route):
69 self.message = 'Route already exists : "%s"' % route
71 class Route(Sequence):
73 def __init__(self, net_addr, prefix, gateway):
74 self.net_addr = net_addr
76 self.gateway = gateway
79 return(self.addr, self.prefix, self.gateway)
81 def __cmp__(self, other):
82 if self.net_addr == other.net_addr \
83 and self.prefix == other.prefix \
84 and self.gateway == other.gateway:
86 return cmp(id(self), id(other))
88 class RouteHandler(Handler):
90 def __init__(self, devices):
91 self.devices = devices
93 @handler(u'Adds a route to a device')
94 def add(self, device, net_addr, prefix, gateway):
95 if not device in self.devices:
96 raise DeviceNotFoundError(device)
97 r = Route(net_addr, prefix, gateway)
99 self.devices[device].routes.index(r)
100 raise RouteAlreadyExistsError(net_addr + '/' + prefix + '->' + gateway)
102 self.devices[device].routes.append(r)
104 @handler(u'Deletes a route from a device')
105 def delete(self, device, net_addr, prefix, gateway):
106 if not device in self.devices:
107 raise DeviceNotFoundError(device)
108 r = Route(net_addr, prefix, gateway)
110 self.devices[device].routes.remove(r)
112 raise RouteNotFoundError(net_addr + '/' + prefix + '->' + gateway)
114 @handler(u'Flushes routes from a device')
115 def flush(self, device):
116 if not device in self.devices:
117 raise DeviceNotFoundError(device)
118 self.devices[device].routes = list()
121 @handler(u'List routes')
122 def list(self, device):
124 k = self.devices[device].routes.keys()
129 @handler(u'Get information about all routes')
132 k = self.devices[device].routes.values()
137 class Address(Sequence):
139 def __init__(self, ip, prefix, broadcast):
142 self.broadcast = broadcast
145 return (self.ip, self.prefix, self.broadcast)
147 class AddressHandler(Handler):
149 def __init__(self, devices):
150 self.devices = devices
152 @handler(u'Adds an address to a device')
153 def add(self, device, ip, prefix, broadcast='+'):
154 if not device in self.devices:
155 raise DeviceNotFoundError(device)
156 if ip in self.devices[device].addrs:
157 raise AddressAlreadyExistsError(ip)
158 self.devices[device].addrs[ip] = Address(ip, prefix, broadcast)
160 @handler(u'Deletes an address from a device')
161 def delete(self, device, ip):
162 if not device in self.devices:
163 raise DeviceNotFoundError(device)
164 if not ip in self.devices[device].addrs:
165 raise AddressNotFoundError(ip)
166 del self.devices[device].addrs[ip]
168 @handler(u'Flushes addresses from a device')
169 def flush(self, device):
170 if not device in self.devices:
171 raise DeviceNotFoundError(device)
172 self.devices[device].addrs = dict()
174 @handler(u'List all addresses from a device')
175 def list(self, device):
177 k = self.devices[device].addrs.keys()
182 @handler(u'Get information about addresses from a device')
183 def show(self, device):
185 k = self.devices[device].addrs.values()
190 class Device(Sequence):
192 def __init__(self, name, mac):
199 return (self.name, self.mac)
201 class DeviceHandler(Handler):
203 def __init__(self, devices):
204 # FIXME remove templates to execute commands
205 from mako.template import Template
206 self.devices = devices
207 template_dir = path.join(path.dirname(__file__), 'templates')
208 dev_fn = path.join(template_dir, 'device')
209 self.device_template = Template(filename=dev_fn)
211 @handler(u'Bring the device up')
213 if name in self.devices:
214 print self.device_template.render(dev=name, action='up')
216 raise DeviceNotFoundError(name)
218 @handler(u'Bring the device down')
219 def down(self, name):
220 if name in self.devices:
221 print self.device_template.render(dev=name, action='down')
223 raise DeviceNotFoundError(name)
225 @handler(u'List all devices')
227 return self.devices.keys()
229 @handler(u'Get information about a device')
231 return self.devices.items()
234 p = Popen(('ip', 'link', 'list'), stdout=PIPE, close_fds=True)
235 string = p.stdout.read()
238 i = string.find('eth')
241 m = string.find('link/ether', i+4)
242 mac = string[ m+11 : m+11+17]
243 d[eth] = Device(eth, mac)
244 i = string.find('eth', m+11+17)
247 class IpHandler(Restorable, ConfigWriter, TransactionalHandler):
249 _persistent_attrs = 'devices'
251 _restorable_defaults = dict(devices=get_devices())
253 _config_writer_files = ('device', 'ip_add', 'ip_del', 'ip_flush',
254 'route_add', 'route_del', 'route_flush')
255 _config_writer_tpl_dir = path.join(path.dirname(__file__), 'templates')
257 def __init__(self, pickle_dir='.', config_dir='.'):
258 r"Initialize DhcpHandler object, see class documentation for details."
259 self._persistent_dir = pickle_dir
260 self._config_writer_cfg_dir = config_dir
261 self._config_build_templates()
263 self.addr = AddressHandler(self.devices)
264 self.route = RouteHandler(self.devices)
265 self.dev = DeviceHandler(self.devices)
267 def _write_config(self):
268 r"_write_config() -> None :: Execute all commands."
269 for device in self.devices.values():
270 print self._render_config('route_flush', dict(dev=device.name))
271 print self._render_config('ip_flush', dict(dev=device.name))
272 for address in device.addrs.values():
273 print self._render_config('ip_add', dict(
276 prefix = address.prefix,
277 broadcast = address.broadcast,
280 for route in device.routes:
281 print self._render_config('route_add', dict(
283 net_addr = route.net_addr,
284 prefix = route.prefix,
285 gateway = route.gateway,
290 if __name__ == '__main__':
293 print '----------------------'
295 ip.addr.add('eth0','192.168.0.23','24','192.168.255.255')
296 ip.addr.add('eth0','192.168.0.26','24')
298 ip.route.add('eth0','192.168.0.0','24','192.168.0.1')
299 ip.route.add('eth0','192.168.0.5','24','192.168.0.1')
301 ip.route.flush('eth0')
303 ip.addr.delete('eth0','192.168.0.23')