예제 #1
0
    def update_routing_table(self):
        """ Update the routing table from the first router able to provide
        valid routing information.
        """
        # copied because it can be modified
        copy_of_routers = list(self.routing_table.routers)

        has_tried_initial_routers = False
        if self.missing_writer:
            has_tried_initial_routers = True
            if self.update_routing_table_with_routers(resolve(self.initial_address)):
                return

        if self.update_routing_table_with_routers(copy_of_routers):
            return

        if not has_tried_initial_routers:
            initial_routers = resolve(self.initial_address)
            for router in copy_of_routers:
                if router in initial_routers:
                    initial_routers.remove(router)
            if initial_routers:
                if self.update_routing_table_with_routers(initial_routers):
                    return

        # None of the routers have been successful, so just fail
        raise ServiceUnavailable("Unable to retrieve routing information")
예제 #2
0
 def parse_routing_info(cls, records):
     """ Parse the records returned from a getServers call and
     return a new RoutingTable instance.
     """
     if len(records) != 1:
         raise ProtocolError("Expected exactly one record")
     record = records[0]
     routers = []
     readers = []
     writers = []
     try:
         servers = record["servers"]
         for server in servers:
             role = server["role"]
             addresses = []
             for address in server["addresses"]:
                 addresses.extend(resolve(SocketAddress.parse(address, DEFAULT_PORT)))
             if role == "ROUTE":
                 routers.extend(addresses)
             elif role == "READ":
                 readers.extend(addresses)
             elif role == "WRITE":
                 writers.extend(addresses)
         ttl = record["ttl"]
     except (KeyError, TypeError):
         raise ProtocolError("Cannot parse routing info")
     else:
         return cls(routers, readers, writers, ttl)
예제 #3
0
    def __init__(self, uri, **config):
        self.initial_address = initial_address = SocketAddress.from_uri(
            uri, DEFAULT_PORT)
        self.security_plan = security_plan = SecurityPlan.build(**config)
        self.encrypted = security_plan.encrypted
        routing_context = SocketAddress.parse_routing_context(uri)
        if not security_plan.routing_compatible:
            # this error message is case-specific as there is only one incompatible
            # scenario right now
            raise ValueError(
                "TRUST_ON_FIRST_USE is not compatible with routing")

        def connector(address, error_handler):
            return connect(address, security_plan.ssl_context,
                           urlparse(uri).hostname, error_handler, **config)

        pool = RoutingConnectionPool(connector,
                                     initial_address, routing_context,
                                     *resolve(initial_address), **config)
        try:
            pool.update_routing_table()
        except:
            pool.close()
            raise
        else:
            Driver.__init__(self, pool, **config)
예제 #4
0
 def acquire(self, access_mode=None):
     for address in resolve(self.address):
         try:
             connection = self.acquire_direct(address)  # should always be a resolved address
         except ServiceUnavailable:
             pass
         else:
             return connection
     raise ServiceUnavailable("Cannot acquire connection to {!r}".format(self.address))
예제 #5
0
def connect(address, ssl_context=None, error_handler=None, **config):
    """ Connect and perform a handshake and return a valid Connection object, assuming
    a protocol version can be agreed.
    """

    # Establish a connection to the host and port specified
    # Catches refused connections see:
    # https://docs.python.org/2/library/errno.html
    log_debug("~~ [RESOLVE] %s", address)
    last_error = None
    for resolved_address in resolve(address):
        log_debug("~~ [RESOLVED] %s -> %s", address, resolved_address)
        try:
            s = _connect(resolved_address, **config)
            s, der_encoded_server_certificate = _secure(s, address[0], ssl_context, **config)
            connection = _handshake(s, resolved_address, der_encoded_server_certificate, error_handler, **config)
        except Exception as error:
            last_error = error
        else:
            return connection
    if last_error is None:
        raise ServiceUnavailable("Failed to resolve addresses for %s" % address)
    else:
        raise last_error