Exemplo n.º 1
0
class ZBeaconTest(unittest.TestCase):
    
    def setUp(self, *args, **kwargs):
        ctx = zmq.Context()
        ctx = zmq.Context()
        # two beacon frames
        self.transmit1 = struct.pack('cccb16sH', b'Z', b'R', b'E',
                           1, uuid.uuid4().bytes,
                           socket.htons(9999))
        self.transmit2 = struct.pack('cccb16sH', b'Z', b'R', b'E',
                           1, uuid.uuid4().bytes,
                           socket.htons(9999))

        self.node1 = ZActor(ctx, ZBeacon)
        self.node1.send_unicode("VERBOSE")
        self.node1.send_unicode("CONFIGURE", zmq.SNDMORE)
        self.node1.send(struct.pack("I", 9999))
        print("Hostname 1:", self.node1.recv_unicode())

        self.node2 = ZActor(ctx, ZBeacon)
        self.node2.send_unicode("VERBOSE")
        self.node2.send_unicode("CONFIGURE", zmq.SNDMORE)
        self.node2.send(struct.pack("I", 9999))
        print("Hostname 2:", self.node2.recv_unicode())
    # end setUp

    def tearDown(self):
        self.node1.destroy()
        self.node2.destroy()
    # end tearDown

    def test_node1(self):
        self.node1.send_unicode("PUBLISH", zmq.SNDMORE)
        self.node1.send(self.transmit1)

    def test_node2(self):
        self.node2.send_unicode("PUBLISH", zmq.SNDMORE)
        self.node2.send(self.transmit2)

    def test_recv_beacon1(self):
        self.node1.send_unicode("PUBLISH", zmq.SNDMORE)
        self.node1.send(self.transmit1)
        self.node2.send_unicode("PUBLISH", zmq.SNDMORE)
        self.node2.send(self.transmit2)
        req = self.node1.recv_multipart()
        self.assertEqual(self.transmit2, req[1])
    
    def test_recv_beacon1(self):
        self.node1.send_unicode("PUBLISH", zmq.SNDMORE)
        self.node1.send(self.transmit1)
        self.node2.send_unicode("PUBLISH", zmq.SNDMORE)
        self.node2.send(self.transmit2)
        req = self.node2.recv_multipart()
        self.assertEqual(self.transmit1, req[1])
Exemplo n.º 2
0
class ZBeaconTest(unittest.TestCase):
    def setUp(self, *args, **kwargs):
        ctx = zmq.Context()
        ctx = zmq.Context()
        # two beacon frames
        self.transmit1 = struct.pack("cccb16sH", b"Z", b"R", b"E", 1, uuid.uuid4().bytes, socket.htons(9999))
        self.transmit2 = struct.pack("cccb16sH", b"Z", b"R", b"E", 1, uuid.uuid4().bytes, socket.htons(9999))

        self.node1 = ZActor(ctx, ZBeacon)
        self.node1.send_unicode("VERBOSE")
        self.node1.send_unicode("CONFIGURE", zmq.SNDMORE)
        self.node1.send(struct.pack("I", 9999))
        print("Hostname 1:", self.node1.recv_unicode())

        self.node2 = ZActor(ctx, ZBeacon)
        self.node2.send_unicode("VERBOSE")
        self.node2.send_unicode("CONFIGURE", zmq.SNDMORE)
        self.node2.send(struct.pack("I", 9999))
        print("Hostname 2:", self.node2.recv_unicode())

    # end setUp

    def tearDown(self):
        self.node1.destroy()
        self.node2.destroy()

    # end tearDown

    def test_node1(self):
        self.node1.send_unicode("PUBLISH", zmq.SNDMORE)
        self.node1.send(self.transmit1)

    def test_node2(self):
        self.node2.send_unicode("PUBLISH", zmq.SNDMORE)
        self.node2.send(self.transmit2)

    def test_recv_beacon1(self):
        self.node1.send_unicode("PUBLISH", zmq.SNDMORE)
        self.node1.send(self.transmit1)
        self.node2.send_unicode("PUBLISH", zmq.SNDMORE)
        self.node2.send(self.transmit2)
        req = self.node1.recv_multipart()
        self.assertEqual(self.transmit2, req[1])

    def test_recv_beacon1(self):
        self.node1.send_unicode("PUBLISH", zmq.SNDMORE)
        self.node1.send(self.transmit1)
        self.node2.send_unicode("PUBLISH", zmq.SNDMORE)
        self.node2.send(self.transmit2)
        req = self.node2.recv_multipart()
        self.assertEqual(self.transmit1, req[1])
Exemplo n.º 3
0
class Discover(object):
    def __init__(self, port=8080, *args, **kwargs):
        self._ctx = zmq.Context()
        self._terminated = False  # API shut us down
        self._verbose = False  # Log all traffic (logging module?)
        self.beacon_port = ZRE_DISCOVERY_PORT  # Beacon port number
        self.interval = 0  # Beacon interval 0=default
        self.beacon = None  # Beacon actor
        self.beacon_socket = None  # Beacon socket for polling
        self.poller = zmq.Poller()  # Socket poller
        self.identity = uuid.uuid4()  # Our UUID as object
        self.bound = False
        self.name = str(self.identity)[:6]  # Our public name (default=first 6 uuid chars)
        self.endpoint = ""  # Our public endpoint
        self.port = port  # Our inbox port, if any
        self.status = 0  # Our own change counter
        self.peers = {}  # Hash of known peers, fast lookup
        self.headers = {}  # Our header values
        # TODO: gossip stuff
        # self.start()
        self.run_thread = Thread(target=self.run)
        self.run_thread.start()

        # def __del__(self):
        # destroy beacon

    def start(self):
        # TODO: If application didn't bind explicitly, we grab an ephemeral port
        # on all available network interfaces. This is orthogonal to
        # beaconing, since we can connect to other peers and they will
        # gossip our endpoint to others.
        if self.beacon_port:
            # Start beacon discovery
            self.beacon = ZActor(self._ctx, ZBeacon)

            if self._verbose:
                self.beacon.send_unicode("VERBOSE")


            # Our hostname is provided by zbeacon
            self.beacon.send_unicode("CONFIGURE", zmq.SNDMORE)
            self.beacon.send(struct.pack("I", self.beacon_port))
            hostname = self.beacon.recv_unicode()

            self.endpoint = "tcp://%s:%d" % (hostname, self.port)

            # Set broadcast/listen beacon
            transmit = struct.pack('cccb16sH', b'Z', b'R', b'E',
                                   BEACON_VERSION, self.identity.bytes,
                                   socket.htons(self.port))
            self.beacon.send_unicode("PUBLISH", zmq.SNDMORE)
            self.beacon.send(transmit)
            # construct the header filter  (to discard none zre messages)
            filter = struct.pack("ccc", b'Z', b'R', b'E')
            self.beacon.send_unicode("SUBSCRIBE", zmq.SNDMORE)
            self.beacon.send(filter)

            self.beacon_socket = self.beacon.resolve()
            self.poller.register(self.beacon_socket, zmq.POLLIN)

    def stop(self):
        logger.debug("Pyre node: stopping beacon")
        if self.beacon:
            stop_transmit = struct.pack('cccb16sH', b'Z', b'R', b'E',
                                        BEACON_VERSION, self.identity.bytes,
                                        socket.htons(0))
            self.beacon.send_unicode("PUBLISH", zmq.SNDMORE)
            self.beacon.send(stop_transmit)
            # Give time for beacon to go out
            time.sleep(0.001)
            self._terminated = True
            # Give time for thread to exit
            time.sleep(5)
            self.poller.unregister(self.beacon_socket)
            #self.beacon.send_unicode("$TERM")
            self.beacon.destroy()
            self.beacon = None
            self.beacon_socket = None

        self.beacon_port = 0

    # Find or create peer via its UUID string
    def require_peer(self, identity, endpoint):
        """

        :param identity:
        :param endpoint:
        :return: endpoint of peer
        """
        p = self.peers.get(identity)
        if not p:
            self.peers[identity] = endpoint
        return p


    def get_peers(self):
        return list(self.peers.values())


    #  Remove a peer from our data structures
    def remove_peer(self, peer):
        # To destroy peer, we remove from peers hash table (dict)
        self.peers.pop(peer)

    def recv_beacon(self):
        # Get IP address and beacon of peer
        msgs = self.beacon_socket.recv_multipart()
        ipaddress = msgs.pop(0)
        frame = msgs.pop(0)

        beacon = struct.unpack('cccb16sH', frame)
        # Ignore anything that isn't a valid beacon
        if beacon[3] != BEACON_VERSION:
            logger.warning("Invalid ZRE Beacon version: {0}".format(beacon[3]))
            return

        peer_id = uuid.UUID(bytes=beacon[4])
        port = socket.ntohs(beacon[5])
        # if we receive a beacon with port 0 this means the peer exited
        if port:
            peer = self.require_peer(peer_id, (str(ipaddress.decode('UTF-8')), port))
        else:
            # Zero port means peer is going away; remove it if
            # we had any knowledge of it already
            peer = self.peers.get(peer_id)
            # remove the peer (delete)
            if peer:
                logger.debug("Received 0 port beacon, removing peer {0}".format(peer))
                self.remove_peer(peer_id)

            else:
                logger.warning(self.peers)
                logger.warning("We don't know peer id {0}".format(peer_id))

    # TODO: Handle gossip dat

    # --------------------------------------------------------------------------
    # This is the actor that runs a single node; it uses one thread, creates
    # a zyre_node object at start and destroys that when finishing.
    def run(self):
        while not self._terminated:
            items = dict(self.poller.poll(1000))
            if self.beacon_socket in items and items[self.beacon_socket] == zmq.POLLIN:
                self.recv_beacon()
Exemplo n.º 4
0
class ZBeaconRepeater(object):

    def __init__(self):
        self.dont_ip = os.environ.get('DONT_IP', '').split(' ')
        self.other_repeaters = []
        self.consul = Consul(sys.argv[1])

        self.ctx = zmq.Context()
        self.poller = zmq.Poller()
        
        self.repeater_pub_port = REPEATER_PUB_PORT
        self.pub = self.ctx.socket(zmq.PUB)
        self.pub.bind('tcp://*:%d' % self.repeater_pub_port)

        self.sub = self.ctx.socket(zmq.SUB)
        self.sub.setsockopt(zmq.SUBSCRIBE, b'')
        self.poller.register(self.sub, zmq.POLLIN)

        self.beacon = ZActor(self.ctx, ZBeacon)
        self.beacon.send_unicode('CONFIGURE', zmq.SNDMORE)
        self.beacon.send(struct.pack('I', ZRE_DISCOVERY_PORT))
        self.address = self.beacon.recv_unicode() # Hostname
        filter_ = struct.pack('ccc', b'Z', b'R', b'E')
        self.beacon.send_unicode('SUBSCRIBE',zmq.SNDMORE)
        self.beacon.send(filter_)
        self.beacon_socket = self.beacon.resolve()
        self.poller.register(self.beacon_socket, zmq.POLLIN)

    def _connect_to_repeaters(self):
        logger.debug('Syncing repeaters')
        docker_nodes = self.consul.kv.get('docker/nodes', recurse=True)
        for node in docker_nodes[1]:
            ip = node['Value'].split(':')[0]
            if ip in self.dont_ip:
                continue

            self._connect_to_repeater(ip)

    def _connect_to_repeater(self, ip):
        if ip in self.other_repeaters:
            return

        logger.info('Connecting to repeater %s', ip)
        endpoint = 'tcp://%s:%d' % (ip, self.repeater_pub_port)
        self.sub.connect(endpoint)

        self.other_repeaters.append(ip)

    def run(self):
        try:
            time_sync_repeaters = time.time() + DELAY_SYNC_REPEATERS
            while True:
                if time.time() >= time_sync_repeaters:
                    self._connect_to_repeaters()
                    time_sync_repeaters = time.time() + DELAY_SYNC_REPEATERS

                items = dict(self.poller.poll(0.1))
                while len(items) > 0:
                    for fd, ev in items.items():
                        if (self.sub == fd) and (ev == zmq.POLLIN):
                            data = self.sub.recv_multipart()
                            logger.debug('From SUB: %s', data)
                            self.beacon.send_unicode('SEND BEACON', zmq.SNDMORE)
                            self.beacon.send(data[0])

                        elif (self.beacon_socket == fd) and (ev == zmq.POLLIN):
                            addr, data = self.beacon_socket.recv_multipart()
                            if addr == self.address:
                                continue
                            logger.debug('From UDP: %s', data + addr)
                            self.pub.send(data + addr)

                    items = dict(self.poller.poll(0))
        finally:
            self.beacon.destroy()
            self.sub.close()
            self.pub.close()