]> git.llucax.com Git - software/pymin.git/blob - services/ip/__init__.py
Factored out a lot of common code.
[software/pymin.git] / 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 seqtools import Sequence
7 from dispatcher import handler, HandlerError, Handler
8 from services.util import Restorable, ConfigWriter
9 from services.util import InitdHandler, TransactionalHandler
10
11 __ALL__ = ('IpHandler','Error','DeviceError','DeviceNotFoundError','RouteError','RouteNotFoundError',
12             'RouteAlreadyExistsError','AddressError','AddressNotFoundError','AddressAlreadyExistsError')
13
14 class Error(HandlerError):
15     r"""
16     Error(command) -> Error instance :: Base IpHandler exception class.
17
18     All exceptions raised by the IpHandler inherits from this one, so you can
19     easily catch any IpHandler exception.
20
21     message - A descriptive error message.
22     """
23
24     def __init__(self, message):
25         r"Initialize the Error object. See class documentation for more info."
26         self.message = message
27
28     def __str__(self):
29         return self.message
30
31 class DeviceError(Error):
32
33     def __init__(self, device):
34         self.message = 'Device error : "%s"' % device
35
36 class DeviceNotFoundError(DeviceError):
37
38     def __init__(self, device):
39         self.message = 'Device not found : "%s"' % device
40
41 class AddressError(Error):
42
43     def __init__(self, addr):
44         self.message = 'Address error : "%s"' % addr
45
46 class AddressNotFoundError(AddressError):
47
48     def __init__(self, address):
49         self.message = 'Address not found : "%s"' % address
50
51 class AddressAlreadyExistsError(AddressError):
52
53     def __init__(self, address):
54         self.message = 'Address already exists : "%s"' % address
55
56 class RouteError(Error):
57
58     def __init__(self, route):
59         self.message = 'Route error : "%s"' % route
60
61 class RouteNotFoundError(RouteError):
62
63     def __init__(self, route):
64         self.message = 'Route not found : "%s"' % route
65
66 class RouteAlreadyExistsError(RouteError):
67
68     def __init__(self, route):
69         self.message = 'Route already exists : "%s"' % route
70
71 class Route(Sequence):
72
73     def __init__(self, net_addr, prefix, gateway):
74         self.net_addr = net_addr
75         self.prefix = prefix
76         self.gateway = gateway
77
78     def as_tuple(self):
79         return(self.addr, self.prefix, self.gateway)
80
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:
85             return 0
86         return cmp(id(self), id(other))
87
88 class RouteHandler(Handler):
89
90     def __init__(self, devices):
91         self.devices = devices
92
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)
98         try:
99             self.devices[device].routes.index(r)
100             raise RouteAlreadyExistsError(net_addr + '/' + prefix + '->' + gateway)
101         except ValueError:
102             self.devices[device].routes.append(r)
103
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)
109         try:
110             self.devices[device].routes.remove(r)
111         except ValueError:
112             raise RouteNotFoundError(net_addr + '/' + prefix + '->' + gateway)
113
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()
119
120
121     @handler(u'List routes')
122     def list(self, device):
123         try:
124             k = self.devices[device].routes.keys()
125         except ValueError:
126             k = list()
127         return k
128
129     @handler(u'Get information about all routes')
130     def show(self):
131         try:
132             k = self.devices[device].routes.values()
133         except ValueError:
134             k = list()
135         return k
136
137 class Address(Sequence):
138
139     def __init__(self, ip, prefix, broadcast):
140         self.ip = ip
141         self.prefix = prefix
142         self.broadcast = broadcast
143
144     def as_tuple(self):
145         return (self.ip, self.prefix, self.broadcast)
146
147 class AddressHandler(Handler):
148
149     def __init__(self, devices):
150         self.devices = devices
151
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)
159
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]
167
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()
173
174     @handler(u'List all addresses from a device')
175     def list(self, device):
176         try:
177             k = self.devices[device].addrs.keys()
178         except ValueError:
179             k = list()
180         return k
181
182     @handler(u'Get information about addresses from a device')
183     def show(self, device):
184         try:
185             k = self.devices[device].addrs.values()
186         except ValueError:
187             k = list()
188         return k
189
190 class Device(Sequence):
191
192     def __init__(self, name, mac):
193         self.name = name
194         self.mac = mac
195         self.addrs = dict()
196         self.routes = list()
197
198     def as_tuple(self):
199         return (self.name, self.mac)
200
201 class DeviceHandler(Handler):
202
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)
210
211     @handler(u'Bring the device up')
212     def up(self, name):
213         if name in self.devices:
214             print self.device_template.render(dev=name, action='up')
215         else:
216             raise DeviceNotFoundError(name)
217
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')
222         else:
223             raise DeviceNotFoundError(name)
224
225     @handler(u'List all devices')
226     def list(self):
227         return self.devices.keys()
228
229     @handler(u'Get information about a device')
230     def show(self):
231         return self.devices.items()
232
233 def get_devices():
234     p = Popen(('ip', 'link', 'list'), stdout=PIPE, close_fds=True)
235     string = p.stdout.read()
236     p.wait()
237     d = dict()
238     i = string.find('eth')
239     while i != -1:
240         eth = string[i:i+4]
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)
245     return d
246
247 class IpHandler(Restorable, ConfigWriter, TransactionalHandler):
248
249     _persistent_vars = 'devices'
250
251     _restorable_defaults = dict(devices=get_devices())
252
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')
256
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()
262         self._restore()
263         self.addr = AddressHandler(self.devices)
264         self.route = RouteHandler(self.devices)
265         self.dev = DeviceHandler(self.devices)
266
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(
274                         dev = device.name,
275                         addr = address.ip,
276                         prefix = address.prefix,
277                         broadcast = address.broadcast,
278                     )
279                 )
280             for route in device.routes:
281                 print self._render_config('route_add', dict(
282                         dev = device.name,
283                         net_addr = route.net_addr,
284                         prefix = route.prefix,
285                         gateway = route.gateway,
286                     )
287                 )
288
289
290 if __name__ == '__main__':
291
292     ip = IpHandler()
293     print '----------------------'
294     ip.dev.up('eth0')
295     ip.addr.add('eth0','192.168.0.23','24','192.168.255.255')
296     ip.addr.add('eth0','192.168.0.26','24')
297     ip.commit()
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')
300     ip.commit()
301     ip.route.flush('eth0')
302     ip.commit()
303     ip.addr.delete('eth0','192.168.0.23')
304     ip.commit()
305
306
307
308