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

Side by Side Diff: tools/android/loading/gce/main.py

Issue 1882793006: tools/android/loading Split GoogleAPI wrappers to a separate library (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Review comments Created 4 years, 8 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 | « tools/android/loading/gce/google_storage_accessor.py ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 # Copyright 2016 The Chromium Authors. All rights reserved. 1 # Copyright 2016 The Chromium Authors. All rights reserved.
2 # Use of this source code is governed by a BSD-style license that can be 2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file. 3 # found in the LICENSE file.
4 4
5 import json 5 import json
6 import os 6 import os
7 import re 7 import re
8 import threading 8 import threading
9 import time 9 import time
10 import subprocess 10 import subprocess
11 import sys 11 import sys
12 12
13 from gcloud import storage
14 from gcloud.exceptions import NotFound
15 from oauth2client.client import GoogleCredentials
16
17 # NOTE: The parent directory needs to be first in sys.path to avoid conflicts 13 # NOTE: The parent directory needs to be first in sys.path to avoid conflicts
18 # with catapult modules that have colliding names, as catapult inserts itself 14 # with catapult modules that have colliding names, as catapult inserts itself
19 # into the path as the second element. This is an ugly and fragile hack. 15 # into the path as the second element. This is an ugly and fragile hack.
20 sys.path.insert(0, 16 sys.path.insert(0,
21 os.path.join(os.path.dirname(os.path.realpath(__file__)), os.pardir)) 17 os.path.join(os.path.dirname(os.path.realpath(__file__)), os.pardir))
22 import controller 18 import controller
19 from google_storage_accessor import GoogleStorageAccessor
23 import loading_trace 20 import loading_trace
21 from loading_trace_database import LoadingTraceDatabase
24 import options 22 import options
25 from loading_trace_database import LoadingTraceDatabase
26 23
27 24
28 class ServerApp(object): 25 class ServerApp(object):
29 """Simple web server application, collecting traces and writing them in 26 """Simple web server application, collecting traces and writing them in
30 Google Cloud Storage. 27 Google Cloud Storage.
31 """ 28 """
32 29
33 def __init__(self, configuration_file): 30 def __init__(self, configuration_file):
34 """|configuration_file| is a path to a file containing JSON as described in 31 """|configuration_file| is a path to a file containing JSON as described in
35 README.md. 32 README.md.
36 """ 33 """
37 self._tasks = [] # List of remaining tasks, only modified by _thread. 34 self._tasks = [] # List of remaining tasks, only modified by _thread.
38 self._failed_tasks = [] # Failed tasks, only modified by _thread. 35 self._failed_tasks = [] # Failed tasks, only modified by _thread.
39 self._thread = None 36 self._thread = None
40 self._tasks_lock = threading.Lock() # Protects _tasks and _failed_tasks. 37 self._tasks_lock = threading.Lock() # Protects _tasks and _failed_tasks.
41 self._initial_task_count = -1 38 self._initial_task_count = -1
42 self._start_time = None 39 self._start_time = None
43 print 'Initializing credentials'
44 self._credentials = GoogleCredentials.get_application_default()
45 print 'Reading configuration' 40 print 'Reading configuration'
46 with open(configuration_file) as config_json: 41 with open(configuration_file) as config_json:
47 config = json.load(config_json) 42 config = json.load(config_json)
48 self._project_name = config['project_name']
49 43
50 # Separate the cloud storage path into the bucket and the base path under 44 # Separate the cloud storage path into the bucket and the base path under
51 # the bucket. 45 # the bucket.
52 storage_path_components = config['cloud_storage_path'].split('/') 46 storage_path_components = config['cloud_storage_path'].split('/')
53 self._bucket_name = storage_path_components[0] 47 self._bucket_name = storage_path_components[0]
54 self._base_path_in_bucket = '' 48 self._base_path_in_bucket = ''
55 if len(storage_path_components) > 1: 49 if len(storage_path_components) > 1:
56 self._base_path_in_bucket = '/'.join(storage_path_components[1:]) 50 self._base_path_in_bucket = '/'.join(storage_path_components[1:])
57 if not self._base_path_in_bucket.endswith('/'): 51 if not self._base_path_in_bucket.endswith('/'):
58 self._base_path_in_bucket += '/' 52 self._base_path_in_bucket += '/'
59 53
60 self._src_path = config['src_path'] 54 self._src_path = config['src_path']
55 self._google_storage_accessor = GoogleStorageAccessor(
56 project_name=config['project_name'], bucket_name=self._bucket_name)
61 57
62 # Initialize the global options that will be used during trace generation. 58 # Initialize the global options that will be used during trace generation.
63 options.OPTIONS.ParseArgs([]) 59 options.OPTIONS.ParseArgs([])
64 options.OPTIONS.local_binary = config['chrome_path'] 60 options.OPTIONS.local_binary = config['chrome_path']
65 61
66 def _IsProcessingTasks(self): 62 def _IsProcessingTasks(self):
67 """Returns True if the application is currently processing tasks.""" 63 """Returns True if the application is currently processing tasks."""
68 return self._thread is not None and self._thread.is_alive() 64 return self._thread is not None and self._thread.is_alive()
69 65
70 def _GetStorageClient(self):
71 return storage.Client(project = self._project_name,
72 credentials = self._credentials)
73
74 def _GetStorageBucket(self, storage_client):
75 return storage_client.get_bucket(self._bucket_name)
76
77 def _UploadFile(self, filename_src, filename_dest):
78 """Uploads a file to Google Cloud Storage
79
80 Args:
81 filename_src: name of the local file
82 filename_dest: name of the file in Google Cloud Storage
83
84 Returns:
85 The URL of the file in Google Cloud Storage.
86 """
87 client = self._GetStorageClient()
88 bucket = self._GetStorageBucket(client)
89 blob = bucket.blob(filename_dest)
90 with open(filename_src) as file_src:
91 blob.upload_from_file(file_src)
92 return blob.public_url
93
94 def _UploadString(self, data_string, filename_dest):
95 """Uploads a string to Google Cloud Storage
96
97 Args:
98 data_string: the contents of the file to be uploaded
99 filename_dest: name of the file in Google Cloud Storage
100
101 Returns:
102 The URL of the file in Google Cloud Storage.
103 """
104 client = self._GetStorageClient()
105 bucket = self._GetStorageBucket(client)
106 blob = bucket.blob(filename_dest)
107 blob.upload_from_string(data_string)
108 return blob.public_url
109
110 def _GenerateTrace(self, url, emulate_device, emulate_network, filename, 66 def _GenerateTrace(self, url, emulate_device, emulate_network, filename,
111 log_filename): 67 log_filename):
112 """ Generates a trace on _thread. 68 """ Generates a trace on _thread.
113 69
114 Args: 70 Args:
115 url: URL as a string. 71 url: URL as a string.
116 emulate_device: Name of the device to emulate. Empty for no emulation. 72 emulate_device: Name of the device to emulate. Empty for no emulation.
117 emulate_network: Type of network emulation. Empty for no emulation. 73 emulate_network: Type of network emulation. Empty for no emulation.
118 filename: Name of the file where the trace is saved. 74 filename: Name of the file where the trace is saved.
119 log_filename: Name of the file where standard output and errors are logged 75 log_filename: Name of the file where standard output and errors are logged
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after
203 url = self._tasks[-1] 159 url = self._tasks[-1]
204 local_filename = pattern.sub('_', url) 160 local_filename = pattern.sub('_', url)
205 for repeat in range(repeat_count): 161 for repeat in range(repeat_count):
206 print 'Generating trace for URL: %s' % url 162 print 'Generating trace for URL: %s' % url
207 remote_filename = local_filename + '/' + str(repeat) 163 remote_filename = local_filename + '/' + str(repeat)
208 trace_metadata = self._GenerateTrace( 164 trace_metadata = self._GenerateTrace(
209 url, emulate_device, emulate_network, local_filename, log_filename) 165 url, emulate_device, emulate_network, local_filename, log_filename)
210 if trace_metadata['succeeded']: 166 if trace_metadata['succeeded']:
211 print 'Uploading: %s' % remote_filename 167 print 'Uploading: %s' % remote_filename
212 remote_trace_location = traces_dir + remote_filename 168 remote_trace_location = traces_dir + remote_filename
213 self._UploadFile(local_filename, remote_trace_location) 169 self._google_storage_accessor.UploadFile(local_filename,
170 remote_trace_location)
214 full_cloud_storage_path = ('gs://' + self._bucket_name + '/' + 171 full_cloud_storage_path = ('gs://' + self._bucket_name + '/' +
215 remote_trace_location) 172 remote_trace_location)
216 trace_database.AddTrace(full_cloud_storage_path, trace_metadata) 173 trace_database.AddTrace(full_cloud_storage_path, trace_metadata)
217 else: 174 else:
218 print 'Trace generation failed for URL: %s' % url 175 print 'Trace generation failed for URL: %s' % url
219 self._tasks_lock.acquire() 176 self._tasks_lock.acquire()
220 self._failed_tasks.append({ "url": url, "repeat": repeat}) 177 self._failed_tasks.append({ "url": url, "repeat": repeat})
221 self._tasks_lock.release() 178 self._tasks_lock.release()
222 if os.path.isfile(local_filename): 179 if os.path.isfile(local_filename):
223 self._UploadFile(local_filename, failures_dir + remote_filename) 180 self._google_storage_accessor.UploadFile(local_filename,
181 failures_dir + remote_filename)
224 print 'Uploading log' 182 print 'Uploading log'
225 self._UploadFile(log_filename, logs_dir + remote_filename) 183 self._google_storage_accessor.UploadFile(log_filename,
184 logs_dir + remote_filename)
226 # Pop once task is finished, for accurate status tracking. 185 # Pop once task is finished, for accurate status tracking.
227 self._tasks_lock.acquire() 186 self._tasks_lock.acquire()
228 url = self._tasks.pop() 187 url = self._tasks.pop()
229 self._tasks_lock.release() 188 self._tasks_lock.release()
230 189
231 self._UploadString(json.dumps(trace_database.ToJsonDict(), indent=2), 190 self._google_storage_accessor.UploadString(
232 traces_dir + 'trace_database.json') 191 json.dumps(trace_database.ToJsonDict(), indent=2),
192 traces_dir + 'trace_database.json')
233 193
234 if len(self._failed_tasks) > 0: 194 if len(self._failed_tasks) > 0:
235 print 'Uploading failing URLs' 195 print 'Uploading failing URLs'
236 self._UploadString(json.dumps(self._failed_tasks, indent=2), 196 self._google_storage_accessor.UploadString(
237 failures_dir + 'failures.json') 197 json.dumps(self._failed_tasks, indent=2),
198 failures_dir + 'failures.json')
238 199
239 def _SetTaskList(self, http_body): 200 def _SetTaskList(self, http_body):
240 """Sets the list of tasks and starts processing them 201 """Sets the list of tasks and starts processing them
241 202
242 Args: 203 Args:
243 http_body: JSON dictionary. See README.md for a description of the format. 204 http_body: JSON dictionary. See README.md for a description of the format.
244 205
245 Returns: 206 Returns:
246 A string to be sent back to the client, describing the success status of 207 A string to be sent back to the client, describing the success status of
247 the request. 208 the request.
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after
310 response_headers = [ 271 response_headers = [
311 ('Content-type','text/plain'), 272 ('Content-type','text/plain'),
312 ('Content-Length', str(len(data))) 273 ('Content-Length', str(len(data)))
313 ] 274 ]
314 start_response('200 OK', response_headers) 275 start_response('200 OK', response_headers)
315 return iter([data]) 276 return iter([data])
316 277
317 278
318 def StartApp(configuration_file): 279 def StartApp(configuration_file):
319 return ServerApp(configuration_file) 280 return ServerApp(configuration_file)
OLDNEW
« no previous file with comments | « tools/android/loading/gce/google_storage_accessor.py ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698