Ejemplo n.º 1
0
 def run(self):
     if self.ticket.confirmed and not self.ticket.source == Node.me():
         if self.ticket.destination == Node.me():
             if self.request.remote_ip == '127.0.0.1':
                 log.info("User is canceling %s -- must inform sender",
                         self.ticket)
                 TicketsAPI(self.ticket.source.uri()).cancel(
                         self.ticket.absolute_url())
             else:
                 log.info("%s is being deleted, we need to find another for "
                         "ourselves", self.ticket)
                 try:
                     TicketsHandler.handle_ticket_request(self.ticket.stream,
                             self.ticket.destination)
                 except HTTPError, e:
                     log.warning("We lost %s and couldn't find a "
                             "replacement to failover -- our stream is "
                             "dead: %s", self.ticket, e)
         elif self.request.remote_ip == self.ticket.source.ip_address:
             log.info("%s is being deleted by the source, must inform the "
                     "target %s", self.ticket, self.ticket.destination)
             TicketsAPI(self.ticket.destination.uri()).cancel(
                     self.ticket.absolute_url())
         elif self.request.remote_ip == self.ticket.destination.ip_address:
             log.info("%s is being deleted by the destination, must inform "
                     "the source %s", self.ticket, self.ticket.source)
             TicketsAPI(self.ticket.source.uri()).cancel(
                     self.ticket.absolute_url())
Ejemplo n.º 2
0
 def run(self):
     if self.ticket.confirmed and not self.ticket.source == Node.me():
         if self.ticket.destination == Node.me():
             if self.request.remote_ip == '127.0.0.1':
                 log.info("User is canceling %s -- must inform sender",
                          self.ticket)
                 TicketsAPI(self.ticket.source.uri()).cancel(
                     self.ticket.absolute_url())
             else:
                 log.info(
                     "%s is being deleted, we need to find another for "
                     "ourselves", self.ticket)
                 try:
                     TicketsHandler.handle_ticket_request(
                         self.ticket.stream, self.ticket.destination)
                 except HTTPError, e:
                     log.warning(
                         "We lost %s and couldn't find a "
                         "replacement to failover -- our stream is "
                         "dead: %s", self.ticket, e)
         elif self.request.remote_ip == self.ticket.source.ip_address:
             log.info(
                 "%s is being deleted by the source, must inform the "
                 "target %s", self.ticket, self.ticket.destination)
             TicketsAPI(self.ticket.destination.uri()).cancel(
                 self.ticket.absolute_url())
         elif self.request.remote_ip == self.ticket.destination.ip_address:
             log.info(
                 "%s is being deleted by the destination, must inform "
                 "the source %s", self.ticket, self.ticket.source)
             TicketsAPI(self.ticket.source.uri()).cancel(
                 self.ticket.absolute_url())
Ejemplo n.º 3
0
 def run(self):
     UpstreamCheckThread(self.node, self.upstream_limit).run()
     Node.me(refresh=True)
     self.load_static_bootstrap_nodes()
     self.load_dynamic_bootstrap_nodes()
     self.register_with_supernode()
     self.load_streams()
     session.commit()
Ejemplo n.º 4
0
 def test_already_streaming(self):
     stream = StreamFactory(source=Node.me())
     TicketFactory(stream=stream, source=Node.me(), destination=Node.me())
     tickets_before = Ticket.query.count()
     self.http_client.fetch(HTTPRequest(self.get_url(stream.tickets_url()), "POST", body=""), self.stop)
     response = self.wait()
     eq_(response.code, 200)
     eq_(Ticket.query.count(), tickets_before)
Ejemplo n.º 5
0
 def run(self):
     UpstreamCheckThread(self.node, self.upstream_limit).run()
     Node.me(refresh=True)
     self.load_static_bootstrap_nodes()
     self.load_dynamic_bootstrap_nodes()
     self.register_with_supernode()
     self.load_streams()
     session.commit()
Ejemplo n.º 6
0
 def test_get_streams(self):
     Node.me()
     [StreamFactory() for _ in range(3)]
     response = self.fetch('/streams')
     eq_(response.code, 200)
     result = json.loads(response.body)
     ok_('streams' in result)
     for stream in result['streams']:
         ok_(Stream.get_by(name=stream['name']))
Ejemplo n.º 7
0
 def test_trigger_locally(self):
     stream = StreamFactory(source=Node.me())
     self.http_client.fetch(HTTPRequest(self.get_url(stream.tickets_url()), "POST", body=""), self.stop)
     response = self.wait()
     eq_(response.code, 200)
     result = json.loads(response.body)
     ok_("ticket" in result)
     eq_(result["ticket"]["stream"], stream.slug)
     eq_(result["ticket"]["source"], Node.me().uuid)
     ticket = Ticket.query.first()
     eq_(ticket.stream, stream)
     eq_(ticket.destination, Node.me())
Ejemplo n.º 8
0
    def _cancel_tickets(self):
        for ticket in Ticket.query.filter_by(source=Node.me()).filter(
                Ticket.destination != Node.me()):
            log.info("Cancelling %s", ticket)
            if ticket.destination:
                TicketsAPI(ticket.destination.uri()).cancel(ticket.absolute_url())

        for ticket in Ticket.query.filter_by(destination=Node.me()).filter(
                Ticket.source != Node.me()):
            log.info("Cancelling %s", ticket)
            if ticket.source:
                TicketsAPI(ticket.source.uri()).cancel(ticket.absolute_url())
        Ticket.query.delete()
Ejemplo n.º 9
0
    def _cancel_tickets(self):
        for ticket in Ticket.query.filter_by(source=Node.me()).filter(
                Ticket.destination != Node.me()):
            log.info("Cancelling %s", ticket)
            if ticket.destination:
                TicketsAPI(ticket.destination.uri()).cancel(
                    ticket.absolute_url())

        for ticket in Ticket.query.filter_by(destination=Node.me()).filter(
                Ticket.source != Node.me()):
            log.info("Cancelling %s", ticket)
            if ticket.source:
                TicketsAPI(ticket.source.uri()).cancel(ticket.absolute_url())
        Ticket.query.delete()
Ejemplo n.º 10
0
 def test_other_known_tickets(self):
     node = Node.me()
     node.supernode = True
     stream = StreamFactory()
     existing_ticket = TicketFactory(stream=stream, source=stream.source, hops=1)
     mockito.when(TicketsAPI).create(mockito.any(), destination_uuid=mockito.any()).thenReturn(
         {"source": existing_ticket.destination.uuid, "source_port": 42, "hops": 1}
     )
     tickets_before = Ticket.query.count()
     self.http_client.fetch(HTTPRequest(self.get_url(stream.tickets_url()), "POST", body=""), self.stop)
     response = self.wait()
     eq_(response.code, 200)
     eq_(Ticket.query.count(), tickets_before + 1)
     ticket = Ticket.query.filter_by(destination=Node.me()).first()
     eq_(ticket.source, existing_ticket.destination)
Ejemplo n.º 11
0
 def post(self):
     """Add the node specified in POSTed JSON to the list of known nodes."""
     uuid = self.get_json_argument('uuid')
     if (Node.me().supernode and self.get_json_argument(
                 'primary_supernode_uuid', '') == Node.me().uuid):
         children_count = Node.query.filter_by(primary_supernode=Node.me()
                 ).count()
         if children_count > settings.SUPERNODE_MAX_CHILDREN:
             raise HTTPError(503)
     if not Node.get_by(uuid=uuid):
         # TODO what if supernode changes? need to update
         self.request.arguments.setdefault('ip_address',
                 self.request.remote_ip)
         Node.from_dict(self.request.arguments)
         session.commit()
Ejemplo n.º 12
0
 def queue_tunnel_status_flip(self):
     """If the stream went from disable to enable or vice versa, need to flip
     the status of the tunnel. Also, every local stream needs a local tunnel
     so we have something to control.
     """
     if self.source == Node.me():
         TUNNEL_QUEUE.put(self)
Ejemplo n.º 13
0
    def _load_ticket(self, stream_slug, destination_uuid):
        stream = Stream.get_by(slug=stream_slug)
        if not destination_uuid:
            return Ticket.get_by(stream=stream, destination=Node.me())

        node = Node.get_by(uuid=destination_uuid)
        return Ticket.query.filter_by(stream=stream, destination=node).first()
Ejemplo n.º 14
0
    def _load_ticket(self, stream_slug, destination_uuid):
        stream = Stream.get_by(slug=stream_slug)
        if not destination_uuid:
            return Ticket.get_by(stream=stream, destination=Node.me())

        node = Node.get_by(uuid=destination_uuid)
        return Ticket.query.filter_by(stream=stream, destination=node).first()
Ejemplo n.º 15
0
    def _request_stream_from_others(cls, stream, destination):
        unconfirmed_tickets = cls._request_stream(stream, destination)
        if not unconfirmed_tickets:
            raise HTTPError(412)
        unconfirmed_tickets = set(unconfirmed_tickets)
        bad_tickets = set()
        for ticket in unconfirmed_tickets:
            ticket.source.update_rtt()
            if Node.me().supernode and not ticket.source.rtt:
                log.info(
                    "Informing web server that %s is unresponsive "
                    "and should be deleted", ticket.source)
                NodesAPI(settings.ASTRAL_WEBSERVER).unregister(
                    ticket.source.absolute_url())
                bad_tickets.append(ticket)
        unconfirmed_tickets = unconfirmed_tickets - bad_tickets
        log.debug("Received %d unconfirmed tickets: %s",
                  len(unconfirmed_tickets), unconfirmed_tickets)

        closest = min(unconfirmed_tickets, key=lambda t: t.source.rtt)
        log.debug("Closest ticket of the unconfirmed ones is %s", closest)
        TicketsAPI(closest.source.uri()).confirm(closest.absolute_url())
        closest.confirmed = True
        session.commit()
        for ticket in set(unconfirmed_tickets) - set([closest]):
            TicketsAPI(ticket.source.uri()).cancel(ticket.absolute_url())
            ticket.delete()
        session.commit()
        return closest
Ejemplo n.º 16
0
    def _request_stream_from_others(cls, stream, destination):
            unconfirmed_tickets = cls._request_stream(stream, destination)
            if not unconfirmed_tickets:
                raise HTTPError(412)
            unconfirmed_tickets = set(unconfirmed_tickets)
            bad_tickets = set()
            for ticket in unconfirmed_tickets:
                ticket.source.update_rtt()
                if Node.me().supernode and not ticket.source.rtt:
                    log.info("Informing web server that %s is unresponsive "
                            "and should be deleted", ticket.source)
                    NodesAPI(settings.ASTRAL_WEBSERVER).unregister(
                            ticket.source.absolute_url())
                    bad_tickets.append(ticket)
            unconfirmed_tickets = unconfirmed_tickets - bad_tickets
            log.debug("Received %d unconfirmed tickets: %s",
                    len(unconfirmed_tickets), unconfirmed_tickets)

            closest = min(unconfirmed_tickets, key=lambda t: t.source.rtt)
            log.debug("Closest ticket of the unconfirmed ones is %s", closest)
            TicketsAPI(closest.source.uri()).confirm(closest.absolute_url())
            closest.confirmed = True
            session.commit()
            for ticket in set(unconfirmed_tickets) - set([closest]):
                TicketsAPI(ticket.source.uri()).cancel(ticket.absolute_url())
                ticket.delete()
            session.commit()
            return closest
Ejemplo n.º 17
0
 def test_create(self):
     stream = StreamFactory(source=Node.me())
     node = NodeFactory()
     self.http_client.fetch(
         HTTPRequest(self.get_url(stream.tickets_url()), "POST", body=json.dumps({"destination_uuid": node.uuid})),
         self.stop,
     )
     response = self.wait()
     eq_(response.code, 200)
     result = json.loads(response.body)
     ok_("ticket" in result)
     eq_(result["ticket"]["stream"], stream.slug)
     eq_(result["ticket"]["source"], Node.me().uuid)
     ticket = Ticket.query.first()
     eq_(ticket.stream, stream)
     eq_(ticket.destination, node)
Ejemplo n.º 18
0
 def queue_tunnel_status_flip(self):
     """If the stream went from disable to enable or vice versa, need to flip
     the status of the tunnel. Also, every local stream needs a local tunnel
     so we have something to control.
     """
     if self.source == Node.me():
         TUNNEL_QUEUE.put(self)
Ejemplo n.º 19
0
    def handle_ticket_request(cls, stream, destination):
        log.debug("Trying to create a ticket to serve %s to %s", stream,
                  destination)
        new_ticket = cls._already_streaming(stream, destination)
        if new_ticket:
            log.info("%s already has a ticket for %s (%s)", destination,
                     stream, new_ticket)
            if not new_ticket.source == Node.me():
                log.info("Refreshing with source %s to be sure",
                         new_ticket.source)
                existing_ticket = cls._request_stream_from_node(
                    stream, new_ticket.source, destination)
            else:
                existing_ticket = new_ticket
            if existing_ticket:
                existing_ticket.refreshed = datetime.datetime.now()
                # In case we lost the tunnel, just make sure it exists
                existing_ticket.queue_tunnel_creation()
                session.commit()
                return existing_ticket
            log.info(
                "%s didn't confirm our old ticket %s, must get a new "
                "one", new_ticket.source, new_ticket)

        if stream.source != Node.me():
            new_ticket = cls._offer_ourselves(stream, destination)
            if new_ticket:
                log.info("We can stream %s to %s, created %s", stream,
                         destination, new_ticket)
                # In case we lost the tunnel, just make sure it exists
                new_ticket.queue_tunnel_creation()
            elif Node.me().supernode or destination == Node.me():
                log.info(
                    "Propagating the request for streaming %s to %s to "
                    "our other known nodes", stream, destination)
                new_ticket = cls._request_stream_from_others(
                    stream, destination)
            else:
                raise HTTPError(412)
        else:
            new_ticket = Ticket(stream=stream,
                                source_port=stream.source_port,
                                destination=destination)
            log.info("%s is the source of %s, created %s", Node.me(), stream,
                     new_ticket)
        session.commit()
        return new_ticket
Ejemplo n.º 20
0
    def _offer_ourselves(cls, stream, destination):
        tickets = Ticket.query.filter_by(source=Node.me())
        if (tickets.count() >= settings.OUTGOING_STREAM_LIMIT
                or Node.me().upstream and tickets.count()
                    * settings.STREAM_BITRATE > Node.me().upstream):
            log.info("Can't stream %s to %s, already at limit", stream,
                    destination)
            raise HTTPError(412)

        ticket = Ticket.get_by(stream=stream, destination=Node.me())
        if ticket:
            new_ticket = Ticket(stream=stream, destination=destination,
                    source_port=ticket.source_port, hops=ticket.hops + 1)
            log.info("We are receiving %s and have room to forward -- "
                "created %s to potentially forward to %s", stream, new_ticket,
                destination)
            return new_ticket
Ejemplo n.º 21
0
 def _request_stream_from_supernodes(cls, stream, destination,
         unconfirmed_tickets=None):
     tickets = []
     for supernode in Node.supernodes():
         if supernode != Node.me() and not cls._already_ticketed(
                 unconfirmed_tickets, destination):
             tickets.append(cls._request_stream_from_node(stream,
                 supernode, destination))
     return filter(None, tickets)
Ejemplo n.º 22
0
 def test_delete(self):
     node = Node.me()
     ticket = TicketFactory(destination=node)
     self.http_client.fetch(HTTPRequest(
         self.get_url(ticket.absolute_url()), 'DELETE'), self.stop)
     response = self.wait()
     eq_(response.code, 200)
     eq_(Ticket.get_by(id=ticket.id), None)
     ok_(Stream.get_by(slug=ticket.stream.slug))
Ejemplo n.º 23
0
    def handle_ticket_request(cls, stream, destination):
        log.debug("Trying to create a ticket to serve %s to %s",
                stream, destination)
        new_ticket = cls._already_streaming(stream, destination)
        if new_ticket:
            log.info("%s already has a ticket for %s (%s)", destination,
                    stream, new_ticket)
            if not new_ticket.source == Node.me():
                log.info("Refreshing with source %s to be sure",
                        new_ticket.source)
                existing_ticket = cls._request_stream_from_node(stream,
                        new_ticket.source, destination)
            else:
                existing_ticket = new_ticket
            if existing_ticket:
                existing_ticket.refreshed = datetime.datetime.now()
                # In case we lost the tunnel, just make sure it exists
                existing_ticket.queue_tunnel_creation()
                session.commit()
                return existing_ticket
            log.info("%s didn't confirm our old ticket %s, must get a new "
                    "one", new_ticket.source, new_ticket)

        if stream.source != Node.me():
            new_ticket = cls._offer_ourselves(stream, destination)
            if new_ticket:
                log.info("We can stream %s to %s, created %s",
                    stream, destination, new_ticket)
                # In case we lost the tunnel, just make sure it exists
                new_ticket.queue_tunnel_creation()
            elif Node.me().supernode or destination == Node.me():
                log.info("Propagating the request for streaming %s to %s to "
                        "our other known nodes", stream, destination)
                new_ticket = cls._request_stream_from_others(stream,
                        destination)
            else:
                raise HTTPError(412)
        else:
            new_ticket = Ticket(stream=stream, source_port=stream.source_port,
                    destination=destination)
            log.info("%s is the source of %s, created %s", Node.me(),
                    stream, new_ticket)
        session.commit()
        return new_ticket
Ejemplo n.º 24
0
 def test_delete(self):
     node = Node.me()
     ticket = TicketFactory(destination=node)
     self.http_client.fetch(
         HTTPRequest(self.get_url(ticket.absolute_url()), 'DELETE'),
         self.stop)
     response = self.wait()
     eq_(response.code, 200)
     eq_(Ticket.get_by(id=ticket.id), None)
     ok_(Stream.get_by(slug=ticket.stream.slug))
Ejemplo n.º 25
0
    def _offer_ourselves(cls, stream, destination):
        tickets = Ticket.query.filter_by(source=Node.me())
        if (tickets.count() >= settings.OUTGOING_STREAM_LIMIT
                or Node.me().upstream and tickets.count() *
                settings.STREAM_BITRATE > Node.me().upstream):
            log.info("Can't stream %s to %s, already at limit", stream,
                     destination)
            raise HTTPError(412)

        ticket = Ticket.get_by(stream=stream, destination=Node.me())
        if ticket:
            new_ticket = Ticket(stream=stream,
                                destination=destination,
                                source_port=ticket.source_port,
                                hops=ticket.hops + 1)
            log.info(
                "We are receiving %s and have room to forward -- "
                "created %s to potentially forward to %s", stream, new_ticket,
                destination)
            return new_ticket
Ejemplo n.º 26
0
 def test_confirm(self):
     node = Node.me()
     ticket = TicketFactory(destination=node, confirmed=False)
     data = {'confirmed': True}
     eq_(ticket.confirmed, False)
     self.http_client.fetch(HTTPRequest(
         self.get_url(ticket.absolute_url()), 'PUT', body=json.dumps(data)),
         self.stop)
     response = self.wait()
     eq_(response.code, 200)
     eq_(ticket.confirmed, True)
Ejemplo n.º 27
0
 def _handle_ticket(self, ticket):
     # reload to get a new database session
     ticket = Ticket.get_by(id=ticket.id)
     if ticket.source == Node.me():
         source_ip = "127.0.0.1"
     else:
         source_ip = ticket.source.ip_address
     try:
         port = self.create_tunnel(ticket.id, source_ip, ticket.source_port,
                                   self.tunnels)
     except Exception, e:
         log.warning("Couldn't create a tunnel for %s: %s", ticket, e)
Ejemplo n.º 28
0
 def _request_stream_from_supernodes(cls,
                                     stream,
                                     destination,
                                     unconfirmed_tickets=None):
     tickets = []
     for supernode in Node.supernodes():
         if supernode != Node.me() and not cls._already_ticketed(
                 unconfirmed_tickets, destination):
             tickets.append(
                 cls._request_stream_from_node(stream, supernode,
                                               destination))
     return filter(None, tickets)
Ejemplo n.º 29
0
 def test_confirm(self):
     node = Node.me()
     ticket = TicketFactory(destination=node, confirmed=False)
     data = {'confirmed': True}
     eq_(ticket.confirmed, False)
     self.http_client.fetch(
         HTTPRequest(self.get_url(ticket.absolute_url()),
                     'PUT',
                     body=json.dumps(data)), self.stop)
     response = self.wait()
     eq_(response.code, 200)
     eq_(ticket.confirmed, True)
Ejemplo n.º 30
0
 def test_get(self):
     node = Node.me()
     ticket = TicketFactory(destination=node)
     mockito.when(TicketsAPI).create(mockito.any(),
             destination_uuid=mockito.any()).thenReturn(
                     {'source': ticket.destination.uuid,
                         'source_port': ticket.source_port,
                         'hops': ticket.hops})
     response = self.fetch(ticket.absolute_url())
     eq_(response.code, 200)
     result = json.loads(response.body)
     ok_('ticket' in result)
     eq_(result['ticket']['stream'], ticket.stream.slug)
Ejemplo n.º 31
0
 def test_remote_source(self):
     node = Node.me()
     node.supernode = True
     remote_node = NodeFactory()
     mockito.when(TicketsAPI).create(mockito.any(), destination_uuid=mockito.any()).thenReturn(
         {"source": remote_node.uuid, "source_port": 42, "hops": 1}
     )
     stream = StreamFactory()
     tickets_before = Ticket.query.count()
     self.http_client.fetch(HTTPRequest(self.get_url(stream.tickets_url()), "POST", body=""), self.stop)
     response = self.wait()
     eq_(response.code, 200)
     eq_(Ticket.query.count(), tickets_before + 1)
Ejemplo n.º 32
0
 def _handle_ticket(self, ticket):
     # reload to get a new database session
     ticket = Ticket.get_by(id=ticket.id)
     if ticket.source == Node.me():
         source_ip = "127.0.0.1"
     else:
         source_ip = ticket.source.ip_address
     try:
         port = self.create_tunnel(ticket.id, source_ip,
                 ticket.source_port, self.tunnels)
     except Exception, e:
         log.warning("Couldn't create a tunnel for %s: %s",
                 ticket, e)
Ejemplo n.º 33
0
 def _request_stream_from_node(cls, stream, node, destination,
         existing_ticket=None):
     if not node or node == Node.me() or node == destination:
         return
     log.info("Requesting %s from the node %s, to be delivered to %s",
             stream, node, destination)
     try:
         ticket_data = TicketsAPI(node.uri()).create(stream.tickets_url(),
                 destination_uuid=destination.uuid)
     except RequestError, e:
         log.info("Couldn't connect to %s to ask for %s -- deleting "
                 "the node from the database", node, stream)
         log.debug("Node returned: %s", e)
         node.delete()
Ejemplo n.º 34
0
 def test_get(self):
     node = Node.me()
     ticket = TicketFactory(destination=node)
     mockito.when(TicketsAPI).create(
         mockito.any(), destination_uuid=mockito.any()).thenReturn({
             'source':
             ticket.destination.uuid,
             'source_port':
             ticket.source_port,
             'hops':
             ticket.hops
         })
     response = self.fetch(ticket.absolute_url())
     eq_(response.code, 200)
     result = json.loads(response.body)
     ok_('ticket' in result)
     eq_(result['ticket']['stream'], ticket.stream.slug)
Ejemplo n.º 35
0
 def _request_stream_from_node(cls,
                               stream,
                               node,
                               destination,
                               existing_ticket=None):
     if not node or node == Node.me() or node == destination:
         return
     log.info("Requesting %s from the node %s, to be delivered to %s",
              stream, node, destination)
     try:
         ticket_data = TicketsAPI(node.uri()).create(
             stream.tickets_url(), destination_uuid=destination.uuid)
     except RequestError, e:
         log.info(
             "Couldn't connect to %s to ask for %s -- deleting "
             "the node from the database", node, stream)
         log.debug("Node returned: %s", e)
         node.delete()
Ejemplo n.º 36
0
 def get(self, stream_slug, destination_uuid=None):
     ticket = self._load_ticket(stream_slug, destination_uuid)
     if ticket:
         # TODO this block is somewhat duplicated from TicketsHandler.post,
         # where we refresh an existing ticket.
         if not ticket.source == Node.me():
             log.info("Refreshing %s with the source", ticket)
             ticket = TicketsHandler._request_stream_from_node(ticket.stream,
                     ticket.source, ticket.destination,
                     existing_ticket=ticket)
         if ticket:
             ticket.refreshed = datetime.datetime.now()
             # In case we lost the tunnel, just make sure it exists
             ticket.queue_tunnel_creation()
             session.commit()
             # TODO this is unideal, but we need to get the new port if it
             # changed. combination of sleep and db flush seems to do it
             # somewhat reliably, but it's still a race condition.
             import time
             time.sleep(0.5)
         ticket = self._load_ticket(stream_slug, destination_uuid)
         self.write({'ticket': ticket.to_dict()})
Ejemplo n.º 37
0
 def get(self, stream_slug, destination_uuid=None):
     ticket = self._load_ticket(stream_slug, destination_uuid)
     if ticket:
         # TODO this block is somewhat duplicated from TicketsHandler.post,
         # where we refresh an existing ticket.
         if not ticket.source == Node.me():
             log.info("Refreshing %s with the source", ticket)
             ticket = TicketsHandler._request_stream_from_node(
                 ticket.stream,
                 ticket.source,
                 ticket.destination,
                 existing_ticket=ticket)
         if ticket:
             ticket.refreshed = datetime.datetime.now()
             # In case we lost the tunnel, just make sure it exists
             ticket.queue_tunnel_creation()
             session.commit()
             # TODO this is unideal, but we need to get the new port if it
             # changed. combination of sleep and db flush seems to do it
             # somewhat reliably, but it's still a race condition.
             import time
             time.sleep(0.5)
         ticket = self._load_ticket(stream_slug, destination_uuid)
         self.write({'ticket': ticket.to_dict()})
Ejemplo n.º 38
0
    def post(self):
        """Register a new available stream."""
        # TODO kind of messy way to handle two different data types, but for
        # some reason Torando is loading the name and description as lists
        # instead of strings if they are form encded
        if not hasattr(self.request, 'arguments') or not self.request.arguments:
            self.load_json()
        else:
            self.request.arguments['name'] = self.request.arguments['name'][0]
            self.request.arguments['description'] = (
                    self.request.arguments.get('description', [''])[0])

        self.request.arguments.setdefault('source', Node.me().uuid)
        if Stream.get_by(name=self.request.arguments['name']):
            self.redirect("%s/upload" % settings.ASTRAL_WEBSERVER)
            return
        stream = Stream.from_dict(self.request.arguments)
        try:
            StreamsAPI(settings.ASTRAL_WEBSERVER).create(
                    source_uuid=stream.source.uuid, name=stream.name,
                    slug=stream.slug, description=stream.description)
        except RequestError, e:
            log.warning("Unable to register stream with origin webserver: %s",
                    e)
Ejemplo n.º 39
0
 def setUp(self):
     super(BaseNodeTest, self).setUp()
     self.node = Node.me()
Ejemplo n.º 40
0
                 self.node().primary_supernode = None
             else:
                 self.load_dynamic_bootstrap_nodes(
                     self.node().primary_supernode.uri())
         if not self.node().primary_supernode:
             self.node().supernode = True
             log.info(
                 "No supernode could take us - "
                 "registering ourselves %s as a supernode", self.node())
             self.register_with_origin()
 else:
     log.info("Registering %s as a supernode, my database told me so",
              self.node())
     self.register_with_origin()
     for supernode in Node.supernodes():
         if supernode != Node.me():
             try:
                 NodesAPI(supernode.uri()).register(
                     self.node().to_dict())
             except RequestError, e:
                 log.warning("Can't connect to supernode %s: %s",
                             supernode, e)
                 supernode.delete()
                 log.info(
                     "Informing web server that %s is unresponsive "
                     "and should be deleted", supernode)
                 NodesAPI(settings.ASTRAL_WEBSERVER).unregister(
                     supernode.absolute_url())
             except RequestFailed:
                 log.warning(
                     "%s threw an error - sure it's not "
Ejemplo n.º 41
0
 if not stream:
     log.debug("Couldnt find stream with slug %s anywhere", stream_slug)
     raise HTTPError(404)
 destination_uuid = self.get_json_argument('destination_uuid', '')
 if destination_uuid:
     destination = Node.get_by(uuid=destination_uuid)
     # TODO since we only have the IP, we have to assume the port is 8000
     # to be able to request back to it for more details. hmm.
     # TODO another problem is that the tornado server is (and i should
     # have realized this sooner...) single-threaded, and based on the
     # event model. So the requsting node is blocked waiting for us to
     # responsed, then we go and query it. well, that's deadlock! a
     # workaroud since we're only dealing with single supernode
     # situations is just to query the supernode, since they MUST know
     # about that other node.
     if not destination and Node.me().primary_supernode:
         try:
             log.debug("Don't know of a node with UUID %s for the "
                     "ticket destination -- asking the requester at "
                     "http://%s:%s", destination_uuid,
                     self.request.remote_ip, settings.PORT)
             # TODO here in the future we would change it to the
             # remote_ip. now just does supernode.
             node_data = NodesAPI(Node.me().primary_supernode.uri()
                     ).find(destination_uuid)
         except RequestError, e:
             log.warning("Can't connect to server: %s", e)
         except ResourceNotFound:
             log.debug("Request didn't know of a node with UUID",
                     destination_uuid)
             raise HTTPError(404)
Ejemplo n.º 42
0
 def _already_seeding(cls, ticket):
     return Node.me() in [ticket.destination, ticket.stream.source]
Ejemplo n.º 43
0
 def prime_stream_tunnels(self):
     for stream in Stream.query.filter(Stream.source == Node.me()):
         stream.queue_tunnel_status_flip()
Ejemplo n.º 44
0
                 self.node().primary_supernode = None
             else:
                 self.load_dynamic_bootstrap_nodes(
                         self.node().primary_supernode.uri())
         if not self.node().primary_supernode:
             self.node().supernode = True
             log.info("No supernode could take us - "
                     "registering ourselves %s as a supernode",
                     self.node())
             self.register_with_origin()
 else:
     log.info("Registering %s as a supernode, my database told me so",
             self.node())
     self.register_with_origin()
     for supernode in Node.supernodes():
         if supernode != Node.me():
             try:
                 NodesAPI(supernode.uri()).register(
                         self.node().to_dict())
             except RequestError, e:
                 log.warning("Can't connect to supernode %s: %s",
                         supernode, e)
                 supernode.delete()
                 log.info("Informing web server that %s is unresponsive "
                         "and should be deleted", supernode)
                 NodesAPI(settings.ASTRAL_WEBSERVER).unregister(
                         supernode.absolute_url())
             except RequestFailed:
                 log.warning("%s threw an error - sure it's not "
                         "running on another computer in your LAN with "
                         "the same remote IP?", supernode)
Ejemplo n.º 45
0
 def prime_stream_tunnels(self):
     for stream in Stream.query.filter(Stream.source == Node.me()):
         stream.queue_tunnel_status_flip()
Ejemplo n.º 46
0
 def setUp(self):
     super(TicketsListHandlerTest, self).setUp()
     Node.me()
     [TicketFactory() for _ in range(3)]
Ejemplo n.º 47
0
 def _unregister_from_all(self):
     for node in Node.not_me():
         if node != Node.me().primary_supernode:
             log.info("Unregistering from %s", node)
             NodesAPI(node.uri()).unregister(self.node().absolute_url())
Ejemplo n.º 48
0
 def _already_seeding(cls, ticket):
     return Node.me() in [ticket.destination, ticket.stream.source]
Ejemplo n.º 49
0
 if not stream:
     log.debug("Couldnt find stream with slug %s anywhere", stream_slug)
     raise HTTPError(404)
 destination_uuid = self.get_json_argument('destination_uuid', '')
 if destination_uuid:
     destination = Node.get_by(uuid=destination_uuid)
     # TODO since we only have the IP, we have to assume the port is 8000
     # to be able to request back to it for more details. hmm.
     # TODO another problem is that the tornado server is (and i should
     # have realized this sooner...) single-threaded, and based on the
     # event model. So the requsting node is blocked waiting for us to
     # responsed, then we go and query it. well, that's deadlock! a
     # workaroud since we're only dealing with single supernode
     # situations is just to query the supernode, since they MUST know
     # about that other node.
     if not destination and Node.me().primary_supernode:
         try:
             log.debug(
                 "Don't know of a node with UUID %s for the "
                 "ticket destination -- asking the requester at "
                 "http://%s:%s", destination_uuid,
                 self.request.remote_ip, settings.PORT)
             # TODO here in the future we would change it to the
             # remote_ip. now just does supernode.
             node_data = NodesAPI(
                 Node.me().primary_supernode.uri()).find(
                     destination_uuid)
         except RequestError, e:
             log.warning("Can't connect to server: %s", e)
         except ResourceNotFound:
             log.debug("Request didn't know of a node with UUID",
Ejemplo n.º 50
0
 def test_create_twice_locally(self):
     stream = StreamFactory(source=Node.me())
     TicketFactory(stream=stream, source=Node.me(), destination=Node.me())
     self.http_client.fetch(HTTPRequest(self.get_url(stream.tickets_url()), "POST", body=""), self.stop)
     response = self.wait()
     eq_(response.code, 200)
Ejemplo n.º 51
0
 def node(self):
     return Node.get_by(uuid=self.uuid) or Node.me(uuid_override=self.uuid)