class FakeAsyncConfig(object): """Fake class for the configuration of service addresses.""" core_services = { ServiceCoord("Service", 0): Address("0.0.0.0", 0), ServiceCoord("Service", 1): Address("0.0.0.1", 1), } other_services = {}
def test_success(self): """Test success cases.""" self.assertEqual( get_service_address(ServiceCoord("Service", 0)), Address("0.0.0.0", 0)) self.assertEqual( get_service_address(ServiceCoord("Service", 1)), Address("0.0.0.1", 1))
def __init__(self, shard=0, listen_on_address=None): signal.signal(signal.SIGINT, lambda unused_x, unused_y: self.exit()) self.name = self.__class__.__name__ self.shard = shard self._my_coord = ServiceCoord(self.name, self.shard) # Dictionaries of (to be) connected RemoteServiceClients. self.remote_services = {} self.initialize_logging() # We setup the listening address for services which want to # connect with us. try: address = get_service_address(self._my_coord) except KeyError: raise ConfigError("Unable to find address for service %r. " "Is it specified in core_services in cms.conf?" % (self._my_coord,)) logger.info("--- %s %s %s", self.name, listen_on_address, address) if listen_on_address is not None: self.rpc_server = StreamServer( Address(listen_on_address, address.port), self._connection_handler) else: self.rpc_server = StreamServer(address, self._connection_handler) self.backdoor = None
def test_background_connect(self, socket_mock): # Patch the connect method of sockets so that it blocks until # we set the done_event (we will do so at the end of the test). connect_mock = socket_mock.return_value.connect done_event = gevent.event.Event() connect_mock.side_effect = lambda _: done_event.wait() # Connect to the RPC server in non-blocking mode and make sure # that we indeed don't block (i.e., take more than 0.001s). with gevent.Timeout(0.001) as timeout: try: client = self.get_client(ServiceCoord("Foo", 0), block=False) except gevent.Timeout as t: if t is not timeout: raise self.fail("Connecting blocks") # As socket.connect() never returned, the RPC client cannot have # connected. self.assertFalse(client.connected) # Unblock the socket's connect method and make sure it actually # got called (otherwise this whole tests is pointless). Also, # yield to other greenlets so that they can be awoken after the # event triggered. done_event.set() gevent.sleep() connect_mock.assert_called_once_with(Address(self.host, self.port))
def setUpService(self, timeout=None, batch=False): self.get_service_address.return_value = Address('127.0.0.1', '12345') # By default, do not rely on the periodic job to trigger # operations. self.service = FakeTriggeredService(0, timeout) for notifier in self.notifiers: self.service.add_executor(FakeExecutor(notifier))
def _connection_handler(self, sock, address): """Receive and act upon an incoming connection. A new RemoteServiceServer is spawned to take care of the new connection. """ address = Address(address[0], address[1]) remote_service = RemoteServiceServer(self, address) remote_service.handle(sock)
def _load_unique(self, path): """Populate the Config class with everything that sits inside the JSON file path (usually something like /etc/cms.conf). The only pieces of data treated differently are the elements of core_services and other_services that are sent to async config. Services whose name begins with an underscore are ignored, so they can be commented out in the configuration file. path (string): the path of the JSON config file. """ # Load config file dic = json.load(open(path)) # Put core and test services in async_config, ignoring those # whose name begins with "_" for service in dic["core_services"]: if service.startswith("_"): continue for shard_number, shard in \ enumerate(dic["core_services"][service]): coord = ServiceCoord(service, shard_number) self.async.core_services[coord] = Address(*shard) del dic["core_services"] for service in dic["other_services"]: if service.startswith("_"): continue for shard_number, shard in \ enumerate(dic["other_services"][service]): coord = ServiceCoord(service, shard_number) self.async.other_services[coord] = Address(*shard) del dic["other_services"] # Put everything else. for key in dic: setattr(self, key, dic[key])
def __init__(self, remote_service_coord, auto_retry=None): """Initialization. This constructor does not call the parent constructor, because it would fail (as the service coord are not in the configuration). This is potentially a problem, but as this client will never connect not many member variable access are performed. """ RemoteServiceBase.__init__(self, Address("None", 0)) self.remote_service_coord = remote_service_coord self.pending_outgoing_requests = dict() self.pending_outgoing_requests_results = dict() self.auto_retry = auto_retry
def _connection_handler(self, sock, address): """Receive and act upon an incoming connection. A new RemoteServiceServer is spawned to take care of the new connection. """ try: ipaddr, port = address ipaddr = gevent.socket.gethostbyname(ipaddr) address = Address(ipaddr, port) except socket.error: logger.warning("Unexpected error.", exc_info=True) return remote_service = RemoteServiceServer(self, address) remote_service.handle(sock)
def spawn_listener(self, host="127.0.0.1", port=0): """Start listening on the given host and port. Each incoming connection will cause a RemoteServiceServer to be instantiated (and therefore a greenlet to be spawned) and to be inserted in self.servers. The listening host and port will also be stored as self.host and self.port. host (string): the hostname or IP address port (int): the port (0 causes any available port to be chosen) """ self._server = StreamServer((host, port), self.handle_new_connection) self._server.start() self.host = self._server.server_host self.port = self._server.server_port self.mock.return_value = Address(self.host, self.port)
def handle_accept(self): """Handle a connection request. It creates a RemoteService to manage the connection. """ try: connection, address = self.accept() except socket.error: logger.warning("Error: %s" % (traceback.format_exc())) return try: ipaddr, port = address ipaddr = socket.gethostbyname(ipaddr) address = Address(ipaddr, port) except: logger.warning("Error: %s" % (traceback.format_exc())) return remote_service = RemoteService(self._service, address=address) remote_service._initialize_channel(connection) self.connected = True