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, \
9 TransactionalHandler, SubHandler, call, \
10 get_network_devices, ListComposedSubHandler, \
11 DictComposedSubHandler, ExecutionError
13 __all__ = ('QoSHandler',)
15 class DeviceError(HandlerError):
17 def __init__(self, dev):
18 self.message = u'Devive error : "%s"' % dev
21 class DeviceNotFoundError(DeviceError):
23 def __init__(self, dev):
24 self.message = u'Device not found : "%s"' % dev
27 class ClassError(HandlerError):
29 def __init__(self, cls):
30 self.message = u'Class error : "%s"' % cls
33 class ClassNotFoundError(ClassError):
35 def __init__(self, cls):
36 self.message = u'Class not found : "%s"' % cls
39 class ClassAlreadyExistsError(ClassError):
41 def __init__(self, cls):
42 self.message = u'Class already exists : "%s"' % cls
45 class HostError(HandlerError):
47 def __init__(self, host):
48 self.message = u'Host error : "%s"' % host
51 class HostNotFoundError(HostError):
53 def __init__(self, ip):
54 self.message = u'Host not found : "%s"' % host
57 class HostAlreadyExistsError(HostError):
59 def __init__(self, ip):
60 self.message = u'Host already exists : "%s"' % host
63 class Class(Sequence):
65 def __init__(self, cid, rate=None):
71 return (self.cid, self.rate)
73 def __cmp__(self, other):
74 if self.cid == other.cid:
76 return cmp(id(self), id(other))
79 class ClassHandler(Handler):
81 def __init__(self, parent):
84 @handler('Adds a class : add <id> <device> <rate>')
85 def add(self, dev, cid, rate):
86 if not dev in self.parent.devices:
87 raise DeviceNotFoundError(dev)
90 self.parent.devices[dev].classes[cid] = Class(cid, rate)
92 raise ClassAlreadyExistsError(cid + ' -> ' + dev)
94 @handler(u'Deletes a class : delete <id> <device>')
95 def delete(self, dev, cid):
96 if not dev in self.parent.devices:
97 raise DeviceNotFoundError(dev)
100 del self.parent.devices[dev].classes[cid]
102 raise ClassNotFoundError(cid + ' -> ' + dev)
104 @handler(u'Lists classes : list <dev>')
107 k = self.parent.devices[dev].classes.items()
113 class Host(Sequence):
115 def __init__(self, ip):
121 def __cmp__(self, other):
122 if self.ip == other.ip:
124 return cmp(id(self), id(other))
127 class HostHandler(SubHandler):
129 def __init__(self, parent):
132 @handler('Adds a host to a class : add <device> <class id> <ip>')
133 def add(self, dev, cid, ip):
134 if not dev in self.parent.devices:
135 raise DeviceNotFoundError(dev)
137 if not cid in self.parent.devices[dev].classes:
138 raise ClassNotFoundError(cid)
141 self.parent.devices[dev].classes[cid].hosts[ip] = Host(ip)
143 raise HostAlreadyExistsError(h + ' -> ' + dev)
145 @handler(u'Lists hosts : list <dev> <class id>')
146 def list(self, dev, cid):
148 k = self.parent.devices[dev].classes[cid].hosts.keys()
154 class Device(Sequence):
156 def __init__(self, name, mac):
159 self.classes = dict()
162 return (self.name, self.mac)
165 class DeviceHandler(SubHandler):
167 handler_help = u"Manage network devices"
169 def __init__(self, parent):
170 # FIXME remove templates to execute commands
171 from mako.template import Template
173 template_dir = path.join(path.dirname(__file__), 'templates')
174 dev_fn = path.join(template_dir, 'device')
175 self.device_template = Template(filename=dev_fn)
177 @handler(u'Bring the device up')
179 if name in self.parent.devices:
181 call(self.device_template.render(dev=name, action='add'), shell=True)
182 except ExecutionError:
185 raise DeviceNotFoundError(name)
187 @handler(u'Bring the device down')
188 def down(self, name):
189 if name in self.parent.devices:
191 call(self.device_template.render(dev=name, action='del'), shell=True)
192 except ExecutionError:
195 raise DeviceNotFoundError(name)
197 @handler(u'List all devices')
199 return self.parent.devices.keys()
201 @handler(u'Get information about a device')
203 return self.parent.devices.items()
206 class QoSHandler(Restorable, ConfigWriter, TransactionalHandler):
208 handler_help = u"Manage QoS devices, classes and hosts"
210 _persistent_attrs = ('devices')
212 _restorable_defaults = dict(
213 devices=dict((dev, Device(dev, mac))
214 for (dev, mac) in get_network_devices().items())
217 _config_writer_files = ('device', 'class_add', 'class_del', 'host_add')
219 _config_writer_tpl_dir = path.join(path.dirname(__file__), 'templates')
221 def __init__(self, pickle_dir='.', config_dir='.'):
222 r"Initialize QoSHandler object, see class documentation for details."
223 self._persistent_dir = pickle_dir
224 self._config_writer_cfg_dir = config_dir
225 self._config_build_templates()
228 self.dev = DeviceHandler(self)
229 self.cls = ClassHandler(self)
230 self.host = HostHandler(self)
232 def _write_config(self):
233 r"_write_config() -> None :: Execute all commands."
234 for device in self.devices.values():
236 call(self._render_config('device', dict(dev=device.name, action='del')), shell=True)
237 except ExecutionError:
241 call(self._render_config('device', dict(dev=device.name, action='add')), shell=True)
242 except ExecutionError:
245 for cls in device.classes.values():
247 call(self._render_config('class_add', dict(
253 except ExecutionError:
256 for host in cls.hosts.values():
258 call(self._render_config('host_add', dict(
264 except ExecutionError:
267 def handle_timer(self):
268 self.refresh_devices()
270 def refresh_devices(self):
271 devices = get_network_devices()
272 #add not registered devices
273 for k, v in devices.items():
274 if k not in self.devices:
275 self.devices[k] = Device(k, v)
277 for k in self.devices.keys():
282 if __name__ == '__main__':
285 print '----------------------'