]> git.llucax.com Git - software/pymin.git/blob - pymin/services/ip/__init__.py
Add support to "operation tagging" to ListSubHandler and DictSubHandler.
[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, SubHandler, 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(SubHandler):
85
86     handler_help = u"Manage IP routes"
87
88     @handler(u'Adds a route to a device')
89     def add(self, device, net_addr, prefix, gateway):
90         if not device in self.parent.devices:
91             raise DeviceNotFoundError(device)
92         r = Route(net_addr, prefix, gateway)
93         try:
94             self.parent.devices[device].routes.index(r)
95             raise RouteAlreadyExistsError(net_addr + '/' + prefix + '->' + gateway)
96         except ValueError:
97             self.parent.devices[device].routes.append(r)
98
99     @handler(u'Deletes a route from a device')
100     def delete(self, device, net_addr, prefix, gateway):
101         if not device in self.parent.devices:
102             raise DeviceNotFoundError(device)
103         r = Route(net_addr, prefix, gateway)
104         try:
105             self.parent.devices[device].routes.remove(r)
106         except ValueError:
107             raise RouteNotFoundError(net_addr + '/' + prefix + '->' + gateway)
108
109     @handler(u'Flushes routes from a device')
110     def flush(self, device):
111         if not device in self.parent.devices:
112             raise DeviceNotFoundError(device)
113         self.parent.devices[device].routes = list()
114
115
116     @handler(u'List routes')
117     def list(self, device):
118         try:
119             k = self.parent.devices[device].routes.keys()
120         except ValueError:
121             k = list()
122         return k
123
124     @handler(u'Get information about all routes')
125     def show(self):
126         try:
127             k = self.parent.devices[device].routes.values()
128         except ValueError:
129             k = list()
130         return k
131
132
133 class Address(Sequence):
134
135     def __init__(self, ip, prefix, broadcast):
136         self.ip = ip
137         self.prefix = prefix
138         self.broadcast = broadcast
139
140     def as_tuple(self):
141         return (self.ip, self.prefix, self.broadcast)
142
143 class AddressHandler(SubHandler):
144
145     handler_help = u"Manage IP addresses"
146
147     @handler(u'Adds an address to a device')
148     def add(self, device, ip, prefix, broadcast='+'):
149         if not device in self.parent.devices:
150             raise DeviceNotFoundError(device)
151         if ip in self.parent.devices[device].addrs:
152             raise AddressAlreadyExistsError(ip)
153         self.parent.devices[device].addrs[ip] = Address(ip, prefix, broadcast)
154
155     @handler(u'Deletes an address from a device')
156     def delete(self, device, ip):
157         if not device in self.parent.devices:
158             raise DeviceNotFoundError(device)
159         if not ip in self.parent.devices[device].addrs:
160             raise AddressNotFoundError(ip)
161         del self.parent.devices[device].addrs[ip]
162
163     @handler(u'Flushes addresses from a device')
164     def flush(self, device):
165         if not device in self.parent.devices:
166             raise DeviceNotFoundError(device)
167         self.parent.devices[device].addrs = dict()
168
169     @handler(u'List all addresses from a device')
170     def list(self, device):
171         try:
172             k = self.parent.devices[device].addrs.keys()
173         except ValueError:
174             k = list()
175         return k
176
177     @handler(u'Get information about addresses from a device')
178     def show(self, device):
179         try:
180             k = self.parent.devices[device].addrs.values()
181         except ValueError:
182             k = list()
183         return k
184
185
186 class Device(Sequence):
187
188     def __init__(self, name, mac):
189         self.name = name
190         self.mac = mac
191         self.addrs = dict()
192         self.routes = list()
193
194     def as_tuple(self):
195         return (self.name, self.mac)
196
197 class DeviceHandler(SubHandler):
198
199     handler_help = u"Manage network devices"
200
201     def __init__(self, parent):
202         # FIXME remove templates to execute commands
203         from mako.template import Template
204         self.parent = parent
205         template_dir = path.join(path.dirname(__file__), 'templates')
206         dev_fn = path.join(template_dir, 'device')
207         self.device_template = Template(filename=dev_fn)
208
209     @handler(u'Bring the device up')
210     def up(self, name):
211         if name in self.devices:
212             call(self.device_template.render(dev=name, action='up'), shell=True)
213         else:
214             raise DeviceNotFoundError(name)
215
216     @handler(u'Bring the device down')
217     def down(self, name):
218         if name in self.devices:
219             call(self.device_template.render(dev=name, action='down'), shell=True)
220         else:
221             raise DeviceNotFoundError(name)
222
223     @handler(u'List all devices')
224     def list(self):
225         return self.devices.keys()
226
227     @handler(u'Get information about a device')
228     def show(self):
229         return self.devices.items()
230
231
232 def get_devices():
233     p = Popen(('ip', 'link', 'list'), stdout=PIPE, close_fds=True)
234     string = p.stdout.read()
235     p.wait()
236     d = dict()
237     i = string.find('eth')
238     while i != -1:
239         eth = string[i:i+4]
240         m = string.find('link/ether', i+4)
241         mac = string[ m+11 : m+11+17]
242         d[eth] = Device(eth, mac)
243         i = string.find('eth', m+11+17)
244     return d
245
246 class IpHandler(Restorable, ConfigWriter, TransactionalHandler):
247
248     handler_help = u"Manage IP devices, addresses and routes"
249
250     _persistent_attrs = 'devices'
251
252     _restorable_defaults = dict(devices=get_devices())
253
254     _config_writer_files = ('device', 'ip_add', 'ip_del', 'ip_flush',
255                             'route_add', 'route_del', 'route_flush')
256     _config_writer_tpl_dir = path.join(path.dirname(__file__), 'templates')
257
258     def __init__(self, pickle_dir='.', config_dir='.'):
259         r"Initialize DhcpHandler object, see class documentation for details."
260         self._persistent_dir = pickle_dir
261         self._config_writer_cfg_dir = config_dir
262         self._config_build_templates()
263         self._restore()
264         self.addr = AddressHandler(self)
265         self.route = RouteHandler(self)
266         self.dev = DeviceHandler(self)
267
268     def _write_config(self):
269         r"_write_config() -> None :: Execute all commands."
270         for device in self.devices.values():
271             call(self._render_config('route_flush', dict(dev=device.name)), shell=True)
272             call(self._render_config('ip_flush', dict(dev=device.name)), shell=True)
273             for address in device.addrs.values():
274                 call(self._render_config('ip_add', dict(
275                         dev = device.name,
276                         addr = address.ip,
277                         prefix = address.prefix,
278                         broadcast = address.broadcast,
279                     )
280                 ), shell=True)
281             for route in device.routes:
282                 call(self._render_config('route_add', dict(
283                         dev = device.name,
284                         net_addr = route.net_addr,
285                         prefix = route.prefix,
286                         gateway = route.gateway,
287                     )
288                 ), shell=True)
289
290
291 if __name__ == '__main__':
292
293     ip = IpHandler()
294     print '----------------------'
295     ip.dev.up('eth0')
296     ip.addr.add('eth0','192.168.0.23','24','192.168.255.255')
297     ip.addr.add('eth0','192.168.0.26','24')
298     ip.commit()
299     ip.route.add('eth0','192.168.0.0','24','192.168.0.1')
300     ip.route.add('eth0','192.168.0.5','24','192.168.0.1')
301     ip.commit()
302     ip.route.flush('eth0')
303     ip.commit()
304     ip.addr.delete('eth0','192.168.0.23')
305     ip.commit()
306
307
308
309