import signal import os import subprocess import ConfigParser as cparser import mininet.node as _node from fibbingnode.misc.mininetlib import get_logger, CFG_KEY, otherIntf,\ L3Router from fibbingnode.misc.utils import del_file, force log = get_logger() class FibbingController(_node.Host, L3Router): instance_count = 0 def __init__(self, name, cfg_path=None, quiet=False, *args, **kwargs): super(FibbingController, self).__init__(name, *args, **kwargs) self.config_params = kwargs.get(CFG_KEY, {}) self.socket_path = "/tmp/%s.socket" % self.name self.cfg_path = "%s.cfg" % self.name if not cfg_path else cfg_path self.instance_number = FibbingController.instance_count self.quiet = quiet FibbingController.instance_count += 1 def start(self): self.cmd('ip', 'link', 'set', 'dev', 'lo', 'up') itfs = self.dump_cfg_info() log.info('Starting southbound controller for ', self.name, '\n') args = ['python', '-m', 'fibbingnode', # '--nocli', '--cfg', self.cfg_path] args.extend(itfs) serr = sout = (None if not self.quiet else open(os.devnull, 'wb')) self.process = self.popen(args, stdin=subprocess.PIPE, stderr=serr, stdout=sout) def stop(self, *args, **kwargs): def _timeout(sig, frame): if not self.process.returncode: raise Exception # TODO figure out why calling process.send_signal(signal.SIGINT) # was not working properly ... (in conjunction with --nocli) signal.signal(signal.SIGALRM, _timeout) signal.alarm(2) force(self.process.communicate, 'exit\n') signal.alarm(0) super(FibbingController, self).stop(*args, **kwargs) def terminate(self, *args, **kwargs): force(self.process.terminate) del_file(self.socket_path) super(FibbingController, self).terminate(*args, **kwargs) def dump_cfg_info(self): cfg = cparser.ConfigParser() for key, val in self.config_params.iteritems(): cfg.set(cparser.DEFAULTSECT, key, val) cfg.set(cparser.DEFAULTSECT, 'json_hostname', 'unix://%s' % self.socket_path) cfg.set(cparser.DEFAULTSECT, 'controller_instance_number', self.instance_number) connected_intfs = [itf for itf in self.intfList() if L3Router.is_l3router_intf(otherIntf(itf)) and itf.name != 'lo'] for itf in connected_intfs: cfg.add_section(itf.name) n = otherIntf(itf).node cfg.set(itf.name, 'hello_interval', n.hello_interval) cfg.set(itf.name, 'dead_interval', n.dead_interval) with open(self.cfg_path, 'w') as f: cfg.write(f) return (itf.name for itf in connected_intfs)