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

Side by Side Diff: testing/legion/client_lib.py

Issue 952893003: Update from https://crrev.com/317530 (Closed) Base URL: https://github.com/domokit/mojo.git@master
Patch Set: Fix gn for nacl Created 5 years, 10 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 unified diff | Download patch
« no previous file with comments | « testing/legion/client_controller.py ('k') | testing/legion/client_rpc_methods.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 # Copyright 2015 The Chromium 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
5 """Defines the client library."""
6
7 import argparse
8 import datetime
9 import logging
10 import os
11 import socket
12 import subprocess
13 import sys
14 import tempfile
15 import threading
16 import xmlrpclib
17
18 #pylint: disable=relative-import
19 import common_lib
20
21 ISOLATE_PY = os.path.join(common_lib.SWARMING_DIR, 'isolate.py')
22 SWARMING_PY = os.path.join(common_lib.SWARMING_DIR, 'swarming.py')
23
24
25 class Error(Exception):
26 pass
27
28
29 class ConnectionTimeoutError(Error):
30 pass
31
32
33 class ClientController(object):
34 """Creates, configures, and controls a client machine."""
35
36 _client_count = 0
37 _controllers = []
38
39 def __init__(self, isolate_file, config_vars, dimensions, priority=100,
40 idle_timeout_secs=common_lib.DEFAULT_TIMEOUT_SECS,
41 connection_timeout_secs=common_lib.DEFAULT_TIMEOUT_SECS,
42 verbosity='ERROR', name=None):
43 assert isinstance(config_vars, dict)
44 assert isinstance(dimensions, dict)
45 type(self)._controllers.append(self)
46 type(self)._client_count += 1
47 self.verbosity = verbosity
48 self._name = name or 'Client%d' % type(self)._client_count
49 self._priority = priority
50 self._isolate_file = isolate_file
51 self._isolated_file = isolate_file + 'd'
52 self._idle_timeout_secs = idle_timeout_secs
53 self._config_vars = config_vars
54 self._dimensions = dimensions
55 self._connect_event = threading.Event()
56 self._connected = False
57 self._ip_address = None
58 self._otp = self._CreateOTP()
59 self._rpc = None
60
61 parser = argparse.ArgumentParser()
62 parser.add_argument('--isolate-server')
63 parser.add_argument('--swarming-server')
64 parser.add_argument('--client-connection-timeout-secs',
65 default=common_lib.DEFAULT_TIMEOUT_SECS)
66 args, _ = parser.parse_known_args()
67
68 self._isolate_server = args.isolate_server
69 self._swarming_server = args.swarming_server
70 self._connection_timeout_secs = (connection_timeout_secs or
71 args.client_connection_timeout_secs)
72
73 @property
74 def name(self):
75 return self._name
76
77 @property
78 def otp(self):
79 return self._otp
80
81 @property
82 def connected(self):
83 return self._connected
84
85 @property
86 def connect_event(self):
87 return self._connect_event
88
89 @property
90 def rpc(self):
91 return self._rpc
92
93 @property
94 def verbosity(self):
95 return self._verbosity
96
97 @verbosity.setter
98 def verbosity(self, level):
99 """Sets the verbosity level as a string.
100
101 Either a string ('INFO', 'DEBUG', etc) or a logging level (logging.INFO,
102 logging.DEBUG, etc) is allowed.
103 """
104 assert isinstance(level, (str, int))
105 if isinstance(level, int):
106 level = logging.getLevelName(level)
107 self._verbosity = level #pylint: disable=attribute-defined-outside-init
108
109 @classmethod
110 def ReleaseAllControllers(cls):
111 for controller in cls._controllers:
112 controller.Release()
113
114 def _CreateOTP(self):
115 """Creates the OTP."""
116 host_name = socket.gethostname()
117 test_name = os.path.basename(sys.argv[0])
118 creation_time = datetime.datetime.utcnow()
119 otp = 'client:%s-host:%s-test:%s-creation:%s' % (
120 self._name, host_name, test_name, creation_time)
121 return otp
122
123 def Create(self):
124 """Creates the client machine."""
125 logging.info('Creating %s', self.name)
126 self._connect_event.clear()
127 self._ExecuteIsolate()
128 self._ExecuteSwarming()
129
130 def WaitForConnection(self):
131 """Waits for the client machine to connect.
132
133 Raises:
134 ConnectionTimeoutError if the client doesn't connect in time.
135 """
136 logging.info('Waiting for %s to connect with a timeout of %d seconds',
137 self._name, self._connection_timeout_secs)
138 self._connect_event.wait(self._connection_timeout_secs)
139 if not self._connect_event.is_set():
140 raise ConnectionTimeoutError('%s failed to connect' % self.name)
141
142 def Release(self):
143 """Quits the client's RPC server so it can release the machine."""
144 if self._rpc is not None and self._connected:
145 logging.info('Releasing %s', self._name)
146 try:
147 self._rpc.Quit()
148 except (socket.error, xmlrpclib.Fault):
149 logging.error('Unable to connect to %s to call Quit', self.name)
150 self._rpc = None
151 self._connected = False
152
153 def _ExecuteIsolate(self):
154 """Executes isolate.py."""
155 cmd = [
156 'python',
157 ISOLATE_PY,
158 'archive',
159 '--isolate', self._isolate_file,
160 '--isolated', self._isolated_file,
161 ]
162
163 if self._isolate_server:
164 cmd.extend(['--isolate-server', self._isolate_server])
165 for key, value in self._config_vars.iteritems():
166 cmd.extend(['--config-var', key, value])
167
168 self._ExecuteProcess(cmd)
169
170 def _ExecuteSwarming(self):
171 """Executes swarming.py."""
172 cmd = [
173 'python',
174 SWARMING_PY,
175 'trigger',
176 self._isolated_file,
177 '--priority', str(self._priority),
178 ]
179
180 if self._isolate_server:
181 cmd.extend(['--isolate-server', self._isolate_server])
182 if self._swarming_server:
183 cmd.extend(['--swarming', self._swarming_server])
184 for key, value in self._dimensions.iteritems():
185 cmd.extend(['--dimension', key, value])
186
187 cmd.extend([
188 '--',
189 '--host', common_lib.MY_IP,
190 '--otp', self._otp,
191 '--verbosity', self._verbosity,
192 '--idle-timeout', str(self._idle_timeout_secs),
193 ])
194
195 self._ExecuteProcess(cmd)
196
197 def _ExecuteProcess(self, cmd):
198 """Executes a process, waits for it to complete, and checks for success."""
199 logging.debug('Running %s', ' '.join(cmd))
200 p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
201 _, stderr = p.communicate()
202 if p.returncode != 0:
203 raise Error(stderr)
204
205 def OnConnect(self, ip_address):
206 """Receives client ip address on connection."""
207 self._ip_address = ip_address
208 self._connected = True
209 self._rpc = common_lib.ConnectToServer(self._ip_address)
210 logging.info('%s connected from %s', self._name, ip_address)
211 self._connect_event.set()
OLDNEW
« no previous file with comments | « testing/legion/client_controller.py ('k') | testing/legion/client_rpc_methods.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698