blob: 3f795070e0eaab400ea748266ea45a3bf25c9282 [file] [log] [blame]
Tom Wai-Hong Tam2b1ef4f2013-07-20 00:54:48 +08001# Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5import httplib
6import socket
Yusuf Mohsinally8d19e3c2013-11-21 14:25:45 -08007import time
Tom Wai-Hong Tam2b1ef4f2013-07-20 00:54:48 +08008import xmlrpclib
9
10from autotest_lib.client.cros.faft.config import Config as ClientConfig
Tom Wai-Hong Tameeed7fb2015-05-08 09:43:29 +080011from autotest_lib.server import autotest
Tom Wai-Hong Tam2b1ef4f2013-07-20 00:54:48 +080012
13
14class _Method:
15 """Class to save the name of the RPC method instead of the real object.
16
17 It keeps the name of the RPC method locally first such that the RPC method
18 can be evalulated to a real object while it is called. Its purpose is to
19 refer to the latest RPC proxy as the original previous-saved RPC proxy may
20 be lost due to reboot.
21
22 The call_method is the method which does refer to the latest RPC proxy.
23 """
24 def __init__(self, call_method, name):
25 self.__call_method = call_method
26 self.__name = name
27
28 def __getattr__(self, name):
29 # Support a nested method.
30 return _Method(self.__call_method, "%s.%s" % (self.__name, name))
31
32 def __call__(self, *args, **dargs):
33 return self.__call_method(self.__name, *args, **dargs)
34
35
36class RPCProxy(object):
37 """Proxy to the FAFTClient RPC server on DUT.
38
39 It acts as a proxy to the FAFTClient on DUT. It is smart enough to:
40 - postpone the RPC connection to the first class method call;
41 - reconnect to the RPC server in case connection lost, e.g. reboot;
42 - always call the latest RPC proxy object.
43 """
44 _client_config = ClientConfig()
45
46 def __init__(self, host):
47 """Constructor.
48
49 @param host: The host object, passed via the test control file.
50 """
51 self._client = host
52 self._faft_client = None
53
54 def __del__(self):
55 self.disconnect()
56
57 def __getattr__(self, name):
58 """Return a _Method object only, not its real object."""
59 return _Method(self.__call_faft_client, name)
60
61 def __call_faft_client(self, name, *args, **dargs):
62 """Make the call on the latest RPC proxy object.
63
64 This method gets the internal method of the RPC proxy and calls it.
65
66 @param name: Name of the RPC method, a nested method supported.
67 @param args: The rest of arguments.
68 @param dargs: The rest of dict-type arguments.
69 @return: The return value of the FAFTClient RPC method.
70 """
71 try:
72 return getattr(self._faft_client, name)(*args, **dargs)
73 except (AttributeError, # _faft_client not initialized, still None
74 socket.error,
75 httplib.BadStatusLine,
76 xmlrpclib.ProtocolError):
77 # Reconnect the RPC server in case connection lost, e.g. reboot.
78 self.connect()
79 # Try again.
80 return getattr(self._faft_client, name)(*args, **dargs)
81
82 def connect(self):
83 """Connect the RPC server."""
Tom Wai-Hong Tameeed7fb2015-05-08 09:43:29 +080084 # Make sure Autotest dependency is there.
85 autotest.Autotest(self._client).install()
Roshan Pius58e5dd32015-10-16 15:16:42 -070086 self._faft_client = self._client.rpc_server_tracker.xmlrpc_connect(
Tom Wai-Hong Tam2b1ef4f2013-07-20 00:54:48 +080087 self._client_config.rpc_command,
88 self._client_config.rpc_port,
89 command_name=self._client_config.rpc_command_short,
90 ready_test_name=self._client_config.rpc_ready_call,
Yusuf Mohsinallyfff89d62013-11-18 16:34:07 -080091 timeout_seconds=self._client_config.rpc_timeout,
Yusuf Mohsinally8d19e3c2013-11-21 14:25:45 -080092 logfile="%s.%s" % (self._client_config.rpc_logfile,
93 time.time())
94 )
Tom Wai-Hong Tam2b1ef4f2013-07-20 00:54:48 +080095
96 def disconnect(self):
97 """Disconnect the RPC server."""
Roshan Pius58e5dd32015-10-16 15:16:42 -070098 self._client.rpc_server_tracker.disconnect(self._client_config.rpc_port)
Tom Wai-Hong Tam2b1ef4f2013-07-20 00:54:48 +080099 self._faft_client = None