Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(186)

Unified Diff: testing/legion/client_rpc_server.py

Issue 890773003: Adding the initial code for Omnibot multi-machine support (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Fixing some silly subprocess code. Created 5 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: testing/legion/client_rpc_server.py
diff --git a/testing/legion/client_rpc_server.py b/testing/legion/client_rpc_server.py
new file mode 100644
index 0000000000000000000000000000000000000000..a80191badb818645692e335c3477ae9bdd0cfe82
--- /dev/null
+++ b/testing/legion/client_rpc_server.py
@@ -0,0 +1,129 @@
+# Copyright 2015 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""The client RPC server code.
+
+This server is an XML-RPC server which serves code from
+client_rpc_methods.RPCMethods.
+
+This server will run until shutdown is called on the server object. This can
+be achieved in 2 ways:
+
+- Calling the Quit RPC method defined in RPCMethods
+- Not receiving any calls within the idle_timeout_secs time.
+"""
+
+import logging
+import threading
+import time
+import xmlrpclib
+import SimpleXMLRPCServer
+import SocketServer
+
+#pylint: disable=relative-import
+import client_rpc_methods
+import common_lib
+
+
+class RequestHandler(SimpleXMLRPCServer.SimpleXMLRPCRequestHandler):
+ """Restricts access to only specified IP address.
+
+ This call assumes the server is RPCServer.
+ """
+
+ def do_POST(self):
+ """Verifies the client is authorized to perform RPCs."""
+ if self.client_address[0] != self.server.authorized_address:
+ logging.error('Received unauthorized RPC request from %s',
+ self.client_address[0])
+ self.send_response(403)
+ response = 'Forbidden'
+ self.send_header('Content-type', 'text/plain')
+ self.send_header('Content-length', str(len(response)))
+ self.end_headers()
+ self.wfile.write(response)
+ else:
+ return SimpleXMLRPCServer.SimpleXMLRPCRequestHandler.do_POST(self)
+
+
+class RPCServer(SimpleXMLRPCServer.SimpleXMLRPCServer,
+ SocketServer.ThreadingMixIn):
+ """Restricts all endpoints to only specified IP addresses."""
+
+ def __init__(self, authorized_address,
+ idle_timeout_secs=common_lib.DEFAULT_TIMEOUT_SECS):
+ SimpleXMLRPCServer.SimpleXMLRPCServer.__init__(
+ self, (common_lib.SERVER_ADDRESS, common_lib.SERVER_PORT),
+ allow_none=True, logRequests=False,
+ requestHandler=RequestHandler)
+
+ self.authorized_address = authorized_address
+ self.idle_timeout_secs = idle_timeout_secs
+ self.register_instance(client_rpc_methods.RPCMethods(self))
+
+ self._shutdown_requested_event = threading.Event()
+ self._rpc_received_event = threading.Event()
+ self._idle_thread = threading.Thread(target=self._CheckForIdleQuit)
+
+ def shutdown(self):
+ """Shutdown the server.
+
+ This overloaded method sets the _shutdown_requested_event to allow the
+ idle timeout thread to quit.
+ """
+ self._shutdown_requested_event.set()
+ SimpleXMLRPCServer.SimpleXMLRPCServer.shutdown(self)
+ logging.info('Server shutdown complete')
+
+ def serve_forever(self, poll_interval=0.5):
+ """Serve forever.
+
+ This overloaded method starts the idle timeout thread before calling
+ serve_forever. This ensures the idle timer thread doesn't get started
+ without the server running.
+
+ Args:
+ poll_interval: The interval to poll for shutdown.
+ """
+ logging.info('RPC server starting')
+ self._idle_thread.start()
+ SimpleXMLRPCServer.SimpleXMLRPCServer.serve_forever(self, poll_interval)
+
+ def _dispatch(self, method, params):
+ """Dispatch the call to the correct method with the provided params.
+
+ This overloaded method adds logging to help trace connection and
+ call problems.
+
+ Args:
+ method: The method name to call.
+ params: A tuple of parameters to pass.
+
+ Returns:
+ The result of the parent class' _dispatch method.
+ """
+ logging.debug('Calling %s%s', method, params)
+ self._rpc_received_event.set()
+ return SimpleXMLRPCServer.SimpleXMLRPCServer._dispatch(self, method, params)
+
+ def _CheckForIdleQuit(self):
+ """Check for, and exit, if the server is idle for too long.
+
+ This method must be run in a separate thread to avoid a deadlock when
+ calling server.shutdown.
+ """
+ timeout = time.time() + self.idle_timeout_secs
+ while time.time() < timeout:
+ if self._shutdown_requested_event.is_set():
+ # An external source called shutdown()
+ return
+ elif self._rpc_received_event.is_set():
+ # An RPC was received, reset the timeout
M-A Ruel 2015/02/03 01:48:41 IMHO I don't think the comment and the following o
Mike Meade 2015/02/03 17:47:57 Done.
+ logging.debug('Resetting the idle timeout')
+ timeout = time.time() + self.idle_timeout_secs
+ self._rpc_received_event.clear()
+ time.sleep(1)
+ # We timed out, kill the server
+ logging.warning('Shutting down the server due to the idle timeout')
+ self.shutdown()

Powered by Google App Engine
This is Rietveld 408576698