Example #1
0
class FMMonitor(threading.Thread):
    def __init__(self, context, hostAddress, riapsHome):
        threading.Thread.__init__(self)
        self.logger = logging.getLogger(__name__)
        self.context = context
        self.hostAddress = hostAddress
        self.riapsHome = riapsHome
        self.control = None
        self.peers = {}  # uuid : address - all peers
        self.groups = {}  # groupName : { peers* } - peers in group
        self.actors = {}  # appName : { actors* }  - actors in apps
        self.uuid = None
        self.logger.info('FMMon:__inited__')

    def setup(self):
        self.logger.info('FMMon:setup()')
        self.control = self.context.socket(zmq.PAIR)
        self.control.bind(const.fmMonitorEndpoint)
        return self.control

    def getUUID(self):
        while self.uuid == None:
            time.sleep(0.1)
        return self.uuid

    def setupApp(self, appName):
        msg = ('setupApp', appName)
        self.control.send_pyobj(msg)

    def cleanupApp(self, appName):
        msg = ('cleanupApp', appName)
        self.control.send_pyobj(msg)

    def addActor(self, appName, actorName):
        msg = ('addActor', appName, actorName)
        self.control.send_pyobj(msg)

    def delActor(self, appName, actorName):
        msg = ('delActor', appName, actorName)
        self.control.send_pyobj(msg)

    def dieActor(self, appName, actorName):
        msg = ('dieActor', appName, actorName)
        self.control.send_pyobj(msg)

    def terminate(self):
        if self.control != None:
            self.control.send_pyobj(('stop', ))
        else:
            self.setup()
            time.sleep(0.1)
            self.control.send_pyobj(('stop', ))

    def groupName(self, appName):
        return b'riaps.' + appName.encode('utf-8')

    def run(self):
        self.zyre = Zyre(None)
        if self.logger.level > 0:
            self.zyre.set_verbose()
            # Zsys.set_logsystem(1)
        else:
            # Zsys.set_logsystem(0)
            pass
        self.uuid = self.zyre.uuid()
        self.zyre.set_interface(Config.NIC_NAME.encode('utf-8'))
        if Config.SECURITY:
            certFile = os.path.join(self.riapsHome, "keys",
                                    const.zmqCertificate)
            cert = czmq.Zcert.load(ctypes.c_char_p(certFile.encode('utf-8')))
            self.zyre.set_zcert(cert)
        self.zyre.set_evasive_timeout(const.peerEvasiveTimeout)
        self.zyre.set_expired_timeout(const.peerExpiredTimeout)
        self.zyre.set_header(b'riaps@' + self.hostAddress.encode('utf-8'),
                             b'hello')
        self.command = self.context.socket(zmq.PAIR)
        self.command.connect(const.fmMonitorEndpoint)
        self.zyre.start()
        self.zyre.join(b'riaps')
        self.zyreSocket = self.zyre.socket()
        self.poller = czmq.Zpoller(zyre.c_void_p(self.command.underlying),
                                   self.zyreSocket, 0)
        while True:
            reader = self.poller.wait(-1)  # Wait forever
            if self.poller.terminated():
                self.logger.warning("FMMon.run - poller terminated")
                break
            if type(
                    reader
            ) == zyre.c_void_p and reader.value == self.command.underlying:
                msg = self.command.recv_pyobj()
                self.logger.info('FMMon.run - command: %s' % str(msg))
                cmd = msg[0]
                if cmd == 'stop':
                    break
                elif cmd == 'setupApp':
                    appName = msg[1]
                    group = self.groupName(appName)
                    self.zyre.join(group)
                    if appName not in self.groups:
                        self.groups[appName] = set()
                        self.actors[appName] = set()
                elif cmd == 'cleanupApp':
                    appName = msg[1]
                    group = self.groupName(appName)
                    self.zyre.leave(group)
                    if appName in self.groups:
                        del self.groups[appName]
                elif cmd == 'addActor':
                    appName, actorName = msg[1:]
                    assert appName in self.groups
                    self.actors[appName].add(actorName)
                    group = self.groupName(appName)
                    arg = "+ %s.%s" % (appName, actorName)
                    self.logger.info("FMMon.addActor.shout: %s" % arg)
                    self.zyre.shouts(group, arg.encode('utf-8'))
                    for peer in self.groups[appName]:
                        self.logger.info(
                            "FMMon.addactor tell %s.%s has peer at %s" %
                            (appName, actorName, str(peer)))
                        info = ('peer+', appName, actorName, peer)
                        self.command.send_pyobj(info)
                elif cmd == 'delActor':
                    appName, actorName = msg[1:]
                    assert appName in self.groups and actorName in self.actors[
                        appName]
                    self.actors[appName].remove(actorName)
                    group = self.groupName(appName)
                    arg = "- %s.%s" % (appName, actorName)
                    self.logger.info("FMMon.delActor.shout: %s" % arg)
                    self.zyre.shouts(group, arg.encode('utf-8'))
                elif cmd == 'dieActor':
                    appName, actorName = msg[1:]
                    assert appName in self.groups and actorName in self.actors[
                        appName]
                    self.actors[appName].remove(actorName)
                    group = self.groupName(appName)
                    arg = "? %s.%s" % (appName, actorName)
                    self.logger.info("FMMon.dieActor.shout: %s" % arg)
                    self.zyre.shouts(group, arg.encode('utf-8'))
                else:
                    pass  # Should be error
            elif reader == self.zyreSocket:
                event = ZyreEvent(self.zyre)
                eType = event.type()
                _pName = event.peer_name()
                pUUID = event.peer_uuid()
                pAddr = event.peer_addr()
                group = event.group()
                _headers = event.headers()
                msg = event.get_msg()
                #                 if eType != b'EVASIVE':
                #                     print("# %s %s %s %s %s %s %s"
                #                           % (str(eType),str(_pName),str(pUUID),str(pAddr),
                #                              str(group),str(_headers),str(msg)))
                if eType == b'ENTER':
                    self.logger.info("FMMon.ENTER %s from %s" %
                                     (str(pUUID), str(pAddr)))
                    self.peers[pUUID] = pAddr
                elif eType == b'JOIN':
                    groupName = group.decode()
                    self.logger.info("FMMon.JOIN %s from %s" %
                                     (str(groupName), str(pUUID)))
                    if groupName == 'riaps':
                        continue  # Joined riaps group - should be validated
                    else:
                        _, appName = groupName.split('.')
                        if appName not in self.groups:
                            self.groups[appName] = {pUUID}
                            if appName not in self.actors:
                                self.actors[appName] = set()
                        else:
                            self.groups[appName].add(pUUID)
                        if appName in self.actors:
                            peer = pUUID
                            for actorName in self.actors[appName]:
                                arg = "+ %s.%s" % (appName, actorName)
                                self.logger.info(
                                    "FMMon.JOIN.whisper: %s to %s " %
                                    (arg, str(peer)))
                                self.zyre.whispers(peer, arg.encode('utf-8'))
                                self.logger.info(
                                    "FMMon.JOIN tell %s.%s has peer at %s" %
                                    (appName, actorName, str(peer)))
                                info = ('peer+', appName, actorName, peer)
                                self.command.send_pyobj(info)
                elif eType == b'LEAVE':
                    groupName = group.decode()
                    self.logger.info("FMMon.LEAVE %s from %s" %
                                     (str(pUUID), str(group)))
                    if groupName == 'riaps':
                        continue  # Left riaps group - should be validated
                    else:
                        _, appName = groupName.split('.')
                        if appName in self.groups:
                            self.groups[appName].remove(pUUID)
                        if appName in self.actors:
                            for actorName in self.actors[appName]:
                                peer = pUUID
                                self.logger.info(
                                    "FMMon.LEAVE tell %s.%s lost peer at %s" %
                                    (appName, actorName, str(peer)))
                                info = ('peer-', appName, actorName, peer)
                                self.command.send_pyobj(info)
                elif eType == b'EXIT':
                    self.logger.info("FMMon.EXIT %s " % (str(pUUID)))
                    for appName, group in self.groups.items():
                        if pUUID in group:
                            if appName in self.actors:
                                for actorName in self.actors[appName]:
                                    peer = pUUID
                                    self.logger.info(
                                        "FMMon.EXIT tell %s.%s lost peer at %s"
                                        % (appName, actorName, str(peer)))
                                    info = ('peer-', appName, actorName, peer)
                                    self.command.send_pyobj(info)
                    del self.peers[pUUID]
                elif eType == b'SHOUT' or eType == b'WHISPER':
                    arg = msg.popstr().decode()
                    self.logger.info("FMMon.SHOUT %s = %s " %
                                     (str(pUUID), arg))
                    peer = pUUID
                    cmd, pair = arg.split(' ')
                    appName, actorName = pair.split('.')
                    head, cast = '?', '?'
                    if cmd == '+':
                        head, cast = 'peer+', ' has peer '
                    elif cmd == '-':
                        head, cast = 'peer-', ' lost peer '
                    elif cmd == '?':
                        head, cast = 'peer-', ' lost peer '
                    if appName not in self.groups:
                        self.groups[appName] = {pUUID}
                    if appName in self.actors:
                        for actorName in self.actors[appName]:
                            self.logger.info("FMMon.%s: tell %s.%s %s %s" %
                                             (eType.decode(), appName,
                                              actorName, cast, str(peer)))
                            info = (head, appName, actorName, peer)
                            self.command.send_pyobj(info)
                else:
                    pass
        self.command.close()
        for appName in self.actors:
            if appName in self.groups:
                group = self.groupName(appName)
                arg = "- %s.%s" % (appName, actorName)
                self.logger.info("FMMon.terminate.shout: %s" % arg)
                self.zyre.shouts(group, arg.encode('utf-8'))
        self.zyre.leave(b'riaps')
        self.zyre.stop()
Example #2
0
class DhtPeerMon(threading.Thread):
    def __init__(self, context, hostAddress, riapsHome, dht, dhtPort):
        threading.Thread.__init__(self, daemon=True)
        self.logger = logging.getLogger(__name__)
        self.context = context
        self.hostAddress = hostAddress
        self.riapsHome = riapsHome
        self.control = None
        self.dht = dht
        self.dhtPort = dhtPort
        self.peers = {}  # uuid : address - all peers
        self.peerGroup = set()  # set(uuid) of peer group members
        self.uuid = None
        self.logger.info('DhtPeerMon:__inited__')

    def setup(self):
        self.logger.info('DhtPeerMon:setup()')
        self.control = self.context.socket(zmq.PAIR)
        self.control.bind(const.discoDhtPeerMonEndpoint)
        return self.control

    def terminate(self):
        if self.control != None:
            self.control.send_pyobj(('stop', ))
        else:
            self.setup()
            time.sleep(0.1)
            self.control.send_pyobj(('stop', ))

    def peerHeaderKey(self, ipAddress):
        return b'riaps_disco@' + ipAddress.encode('utf-8')

    PEERMARK = b'CAFE'
    PEERGROUP = b'riaps_disco'

    def run(self):
        self.zyre = Zyre(None)
        if self.logger.level == logging.DEBUG:
            self.zyre.set_verbose()
        else:
            pass
        self.uuid = self.zyre.uuid()
        self.zyre.set_interface(Config.NIC_NAME.encode('utf-8'))
        if Config.SECURITY:
            certFile = os.path.join(self.riapsHome, "keys",
                                    const.zmqCertificate)
            cert = czmq.Zcert.load(ctypes.c_char_p(certFile.encode('utf-8')))
            self.zyre.set_zcert(cert)
        self.zyre.set_evasive_timeout(const.peerEvasiveTimeout)
        self.zyre.set_expired_timeout(const.peerExpiredTimeout)
        self.zyre.set_header(self.peerHeaderKey(self.hostAddress),
                             self.PEERMARK)
        self.command = self.context.socket(zmq.PAIR)
        self.command.connect(const.discoDhtPeerMonEndpoint)
        self.zyre.start()
        self.zyre.join(self.PEERGROUP)
        self.zyreSocket = self.zyre.socket()
        self.poller = czmq.Zpoller(zyre.c_void_p(self.command.underlying),
                                   self.zyreSocket, 0)
        while True:
            reader = self.poller.wait(-1)  # Wait forever
            if self.poller.terminated():
                self.logger.info("DhtPeerMon.run - poller terminated")
                break
            if type(
                    reader
            ) == zyre.c_void_p and reader.value == self.command.underlying:
                msg = self.command.recv_pyobj()
                self.logger.info('DhtPeerMon.run - command: %s' % str(msg))
                cmd = msg[0]
                if cmd == 'stop':
                    break
                else:
                    pass  # Should be error
            elif reader == self.zyreSocket:
                event = ZyreEvent(self.zyre)
                eType = event.type()
                _pName = event.peer_name()
                pUUID = event.peer_uuid()
                pAddr = event.peer_addr()
                group = event.group()
                _headers = event.headers()
                msg = event.get_msg()
                #                 if eType != b'EVASIVE':
                #                     print("# %s %s %s %s %s %s %s"
                #                           % (str(eType),str(_pName),str(pUUID),str(pAddr),
                #                              str(group),str(_headers),str(msg)))
                if eType == b'ENTER':
                    self.logger.info("DhtPeerMon.ENTER %s from %s" %
                                     (str(pUUID), str(pAddr)))
                    try:
                        pAddrStr = pAddr.decode('UTF-8')
                        (peerIp,
                         _peerPort) = parse.parse("tcp://{}:{}", pAddrStr)
                        peerHeaderKey = self.peerHeaderKey(peerIp)
                        _value = _headers.lookup(peerHeaderKey)
                        if (_value):
                            try:
                                value = ctypes.cast(_value,
                                                    ctypes.c_char_p).value
                                assert value == self.PEERMARK
                                self.peers[pUUID] = peerIp
                                self.logger.info("DhtPeerMon.ENTER valid peer")
                            except:
                                self.logger.info(
                                    "DhtPeerMon.ENTER header value mismatch")
                        else:
                            self.logger.info(
                                "DhtPeerMon.ENTER header key mismatch")
                    except:
                        self.logger.info(
                            "DhtPeerMon.ENTER peer addr parsing error")
                elif pUUID not in self.peers:  # Skip the rest if this is not a peer
                    continue
                elif eType == b'JOIN':
                    groupName = group.decode()
                    peer = pUUID
                    self.logger.info("DhtPeerMon.JOIN %s from %s" %
                                     (str(groupName), str(pUUID)))
                    if groupName != self.PEERGROUP:
                        self.logger.info("DhtPeerMon.JOIN another group")
                        pass
                    else:
                        self.peerGroup.add(peer)
                        self.zyre.whispers(
                            peer,
                            ("%s://%d" %
                             (self.PEERGROUP, self.dhtPort)).encode('utf-8'))
                elif eType == b'SHOUT' or eType == b'WHISPER':
                    arg = msg.popstr().decode()
                    self.logger.info("DhtPeerMon.SHOUT %s = %s " %
                                     (str(pUUID), arg))
                    try:
                        pAddrStr = pAddr.decode('UTF-8')
                        (peerIp,
                         _peerPort) = parse.parse("tcp://{}:{}", pAddrStr)
                        assert peerIp == self.peers[pUUID]
                        peerDhtPort = parse.parse("%s://{}" % self.PEERGROUP,
                                                  arg)
                        if peerDhtPort:
                            self.logger.info("DhtPeerMon.bootstrap %s:%s" %
                                             (peerIp, peerDhtPort))
                            self.dht.bootstrap(str(peerIp), str(peerDhtPort))
                    except:
                        self.logger.error("DhtPeerMon.bootstrap failed")
                elif eType == b'LEAVE':
                    groupName = group.decode()
                    self.logger.info("DhtPeerMon.LEAVE %s from %s" %
                                     (str(pUUID), str(group)))
                    if groupName != self.PEERGROUP:
                        self.logger.info("DhtPeerMon.LEAVE another group")
                        pass
                    else:
                        self.peerGroup.discard(pUUID)
                elif eType == b'EXIT':
                    self.logger.info("DhtPeerMon.EXIT %s " % (str(pUUID)))
                    if pUUID in self.peers:
                        del self.peers[pUUID]
                        self.peerGroup.discard(pUUID)
                else:
                    pass
        self.command.close()
        self.zyre.leave(self.PEERGROUP)
        self.zyre.stop()