]> git.llucax.com Git - software/pymin.git/blob - pymin/services/ip/__init__.py
Raise a CommandNotFoundError if updating an object without update().
[software/pymin.git] / pymin / services / ip / __init__.py
1 # vim: set encoding=utf-8 et sw=4 sts=4 :
2
3 from subprocess import Popen, PIPE
4 from os import path
5
6 from pymin.seqtools import Sequence
7 from pymin.dispatcher import handler, HandlerError, Handler
8 from pymin.services.util import Restorable, ConfigWriter, InitdHandler, \
9                                 TransactionalHandler, call
10
11 __ALL__ = ('IpHandler', 'Error','DeviceError', 'DeviceNotFoundError',
12            'RouteError', 'RouteNotFoundError', 'RouteAlreadyExistsError',
13            'AddressError', 'AddressNotFoundError', 'AddressAlreadyExistsError')
14
15 class Error(HandlerError):
16     r"""
17     Error(command) -> Error instance :: Base IpHandler exception class.
18
19     All exceptions raised by the IpHandler inherits from this one, so you can
20     easily catch any IpHandler exception.
21
22     message - A descriptive error message.
23     """
24     pass
25
26 class DeviceError(Error):
27
28     def __init__(self, device):
29         self.message = u'Device error : "%s"' % device
30
31 class DeviceNotFoundError(DeviceError):
32
33     def __init__(self, device):
34         self.message = u'Device not found : "%s"' % device
35
36 class AddressError(Error):
37
38     def __init__(self, addr):
39         self.message = u'Address error : "%s"' % addr
40
41 class AddressNotFoundError(AddressError):
42
43     def __init__(self, address):
44         self.message = u'Address not found : "%s"' % address
45
46 class AddressAlreadyExistsError(AddressError):
47
48     def __init__(self, address):
49         self.message = u'Address already exists : "%s"' % address
50
51 class RouteError(Error):
52
53     def __init__(self, route):
54         self.message = u'Route error : "%s"' % route
55
56 class RouteNotFoundError(RouteError):
57
58     def __init__(self, route):
59         self.message = u'Route not found : "%s"' % route
60
61 class RouteAlreadyExistsError(RouteError):
62
63     def __init__(self, route):
64         self.message = u'Route already exists : "%s"' % route
65
66
67 class Route(Sequence):
68
69     def __init__(self, net_addr, prefix, gateway):
70         self.net_addr = net_addr
71         self.prefix = prefix
72         self.gateway = gateway
73
74     def as_tuple(self):
75         return(self.addr, self.prefix, self.gateway)
76
77     def __cmp__(self, other):
78         if self.net_addr == other.net_addr \
79                 and self.prefix == other.prefix \
80                 and self.gateway == other.gateway:
81             return 0
82         return cmp(id(self), id(other))
83
84 class RouteHandler(Handler):
85
86     handler_help = u"Manage IP routes"
87
88     def __init__(self, parent):
89         self.parent = parent
90
91     @handler(u'Adds a route to a device')
92     def add(self, device, net_addr, prefix, gateway):
93         if not device in self.parent.devices:
94             raise DeviceNotFoundError(device)
95         r = Route(net_addr, prefix, gateway)
96         try:
97             self.parent.devices[device].routes.index(r)
98             raise RouteAlreadyExistsError(net_addr + '/' + prefix + '->' + gateway)
99         except ValueError:
100             self.parent.devices[device].routes.append(r)
101
102     @handler(u'Deletes a route from a device')
103     def delete(self, device, net_addr, prefix, gateway):
104         if not device in self.parent.devices:
105             raise DeviceNotFoundError(device)
106         r = Route(net_addr, prefix, gateway)
107         try:
108             self.parent.devices[device].routes.remove(r)
109         except ValueError:
110             raise RouteNotFoundError(net_addr + '/' + prefix + '->' + gateway)
111
112     @handler(u'Flushes routes from a device')
113     def flush(self, device):
114         if not device in self.parent.devices:
115             raise DeviceNotFoundError(device)
116         self.parent.devices[device].routes = list()
117
118
119     @handler(u'List routes')
120     def list(self, device):
121         try:
122             k = self.parent.devices[device].routes.keys()
123         except ValueError:
124             k = list()
125         return k
126
127     @handler(u'Get information about all routes')
128     def show(self):
129         try:
130             k = self.parent.devices[device].routes.values()
131         except ValueError:
132             k = list()
133         return k
134
135
136 class Address(Sequence):
137
138     def __init__(self, ip, prefix, broadcast):
139         self.ip = ip
140         self.prefix = prefix
141         self.broadcast = broadcast
142
143     def as_tuple(self):
144         return (self.ip, self.prefix, self.broadcast)
145
146 class AddressHandler(Handler):
147
148     handler_help = u"Manage IP addresses"
149
150     def __init__(self, parent):
151         self.parent = parent
152
153     @handler(u'Adds an address to a device')
154     def add(self, device, ip, prefix, broadcast='+'):
155         if not device in self.parent.devices:
156             raise DeviceNotFoundError(device)
157         if ip in self.parent.devices[device].addrs:
158             raise AddressAlreadyExistsError(ip)
159         self.parent.devices[device].addrs[ip] = Address(ip, prefix, broadcast)
160
161     @handler(u'Deletes an address from a device')
162     def delete(self, device, ip):
163         if not device in self.parent.devices:
164             raise DeviceNotFoundError(device)
165         if not ip in self.parent.devices[device].addrs:
166             raise AddressNotFoundError(ip)
167         del self.parent.devices[device].addrs[ip]
168
169     @handler(u'Flushes addresses from a device')
170     def flush(self, device):
171         if not device in self.parent.devices:
172             raise DeviceNotFoundError(device)
173         self.parent.devices[device].addrs = dict()
174
175     @handler(u'List all addresses from a device')
176     def list(self, device):
177         try:
178             k = self.parent.devices[device].addrs.keys()
179         except ValueError:
180             k = list()
181         return k
182
183     @handler(u'Get information about addresses from a device')
184     def show(self, device):
185         try:
186             k = self.parent.devices[device].addrs.values()
187         except ValueError:
188             k = list()
189         return k
190
191
192 class Device(Sequence):
193
194     def __init__(self, name, mac):
195         self.name = name
196         self.mac = mac
197         self.addrs = dict()
198         self.routes = list()
199
200     def as_tuple(self):
201         return (self.name, self.mac)
202
203 class DeviceHandler(Handler):
204
205     handler_help = u"Manage network devices"
206
207     def __init__(self, parent):
208         # FIXME remove templates to execute commands
209         from mako.template import Template
210         self.parent = parent
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)
214
215     @handler(u'Bring the device up')
216     def up(self, name):
217         if name in self.devices:
218             call(self.device_template.render(dev=name, action='up'), shell=True)
219         else:
220             raise DeviceNotFoundError(name)
221
222     @handler(u'Bring the device down')
223     def down(self, name):
224         if name in self.devices:
225             call(self.device_template.render(dev=name, action='down'), shell=True)
226         else:
227             raise DeviceNotFoundError(name)
228
229     @handler(u'List all devices')
230     def list(self):
231         return self.devices.keys()
232
233     @handler(u'Get information about a device')
234     def show(self):
235         return self.devices.items()
236
237
238 def get_devices():
239     p = Popen(('ip', 'link', 'list'), stdout=PIPE, close_fds=True)
240     string = p.stdout.read()
241     p.wait()
242     d = dict()
243     i = string.find('eth')
244     while i != -1:
245         eth = string[i:i+4]
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)
250     return d
251
252 class IpHandler(Restorable, ConfigWriter, TransactionalHandler):
253
254     handler_help = u"Manage IP devices, addresses and routes"
255
256     _persistent_attrs = 'devices'
257
258     _restorable_defaults = dict(devices=get_devices())
259
260     _config_writer_files = ('device', 'ip_add', 'ip_del', 'ip_flush',
261                             'route_add', 'route_del', 'route_flush')
262     _config_writer_tpl_dir = path.join(path.dirname(__file__), 'templates')
263
264     def __init__(self, pickle_dir='.', config_dir='.'):
265         r"Initialize DhcpHandler object, see class documentation for details."
266         self._persistent_dir = pickle_dir
267         self._config_writer_cfg_dir = config_dir
268         self._config_build_templates()
269         self._restore()
270         self.addr = AddressHandler(self)
271         self.route = RouteHandler(self)
272         self.dev = DeviceHandler(self)
273
274     def _write_config(self):
275         r"_write_config() -> None :: Execute all commands."
276         for device in self.devices.values():
277             call(self._render_config('route_flush', dict(dev=device.name)), shell=True)
278             call(self._render_config('ip_flush', dict(dev=device.name)), shell=True)
279             for address in device.addrs.values():
280                 call(self._render_config('ip_add', dict(
281                         dev = device.name,
282                         addr = address.ip,
283                         prefix = address.prefix,
284                         broadcast = address.broadcast,
285                     )
286                 ), shell=True)
287             for route in device.routes:
288                 call(self._render_config('route_add', dict(
289                         dev = device.name,
290                         net_addr = route.net_addr,
291                         prefix = route.prefix,
292                         gateway = route.gateway,
293                     )
294                 ), shell=True)
295
296
297 if __name__ == '__main__':
298
299     ip = IpHandler()
300     print '----------------------'
301     ip.dev.up('eth0')
302     ip.addr.add('eth0','192.168.0.23','24','192.168.255.255')
303     ip.addr.add('eth0','192.168.0.26','24')
304     ip.commit()
305     ip.route.add('eth0','192.168.0.0','24','192.168.0.1')
306     ip.route.add('eth0','192.168.0.5','24','192.168.0.1')
307     ip.commit()
308     ip.route.flush('eth0')
309     ip.commit()
310     ip.addr.delete('eth0','192.168.0.23')
311     ip.commit()
312
313
314
315