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

Side by Side Diff: tools/telemetry/catapult_base/cloud_storage.py

Issue 1260083007: [Telemetry] Update cloud_storage to use telemetry/third_party/gsutilz/gsutil (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 5 years, 4 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 | « no previous file | 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 2014 The Chromium Authors. All rights reserved. 1 # Copyright 2014 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 """Wrappers for gsutil, for basic interaction with Google Cloud Storage.""" 5 """Wrappers for gsutil, for basic interaction with Google Cloud Storage."""
6 6
7 import collections 7 import collections
8 import contextlib
9 import cStringIO
10 import hashlib 8 import hashlib
11 import logging 9 import logging
12 import os 10 import os
13 import subprocess 11 import subprocess
14 import sys 12 import sys
15 import tarfile
16 import urllib2
17 13
18 from telemetry.core import util 14 from telemetry.core import util
19 from telemetry import decorators 15 from telemetry import decorators
20 from telemetry.internal.util import path 16 from telemetry.internal.util import path
21 17
22 18
23 PUBLIC_BUCKET = 'chromium-telemetry' 19 PUBLIC_BUCKET = 'chromium-telemetry'
24 PARTNER_BUCKET = 'chrome-partner-telemetry' 20 PARTNER_BUCKET = 'chrome-partner-telemetry'
25 INTERNAL_BUCKET = 'chrome-telemetry' 21 INTERNAL_BUCKET = 'chrome-telemetry'
26 22
27 23
28 # Uses ordered dict to make sure that bucket's key-value items are ordered from 24 # Uses ordered dict to make sure that bucket's key-value items are ordered from
29 # the most open to the most restrictive. 25 # the most open to the most restrictive.
30 BUCKET_ALIASES = collections.OrderedDict(( 26 BUCKET_ALIASES = collections.OrderedDict((
31 ('public', PUBLIC_BUCKET), 27 ('public', PUBLIC_BUCKET),
32 ('partner', PARTNER_BUCKET), 28 ('partner', PARTNER_BUCKET),
33 ('internal', INTERNAL_BUCKET), 29 ('internal', INTERNAL_BUCKET),
34 )) 30 ))
35 31
36 32
37 _GSUTIL_URL = 'http://storage.googleapis.com/pub/gsutil.tar.gz' 33 _GSUTIL_PATH = os.path.join(path.GetTelemetryDir(), 'third_party', 'gsutil',
38 _DOWNLOAD_PATH = os.path.join(path.GetTelemetryDir(), 'third_party', 'gsutil') 34 'gsutil')
35
39 # TODO(tbarzic): A workaround for http://crbug.com/386416 and 36 # TODO(tbarzic): A workaround for http://crbug.com/386416 and
40 # http://crbug.com/359293. See |_RunCommand|. 37 # http://crbug.com/359293. See |_RunCommand|.
41 _CROS_GSUTIL_HOME_WAR = '/home/chromeos-test/' 38 _CROS_GSUTIL_HOME_WAR = '/home/chromeos-test/'
42 39
43 40
44 class CloudStorageError(Exception): 41 class CloudStorageError(Exception):
45 @staticmethod 42 @staticmethod
46 def _GetConfigInstructions(gsutil_path): 43 def _GetConfigInstructions():
47 if SupportsProdaccess(gsutil_path) and _FindExecutableInPath('prodaccess'): 44 command = _GSUTIL_PATH
48 return 'Run prodaccess to authenticate.' 45 if util.IsRunningOnCrosDevice():
49 else: 46 command = 'HOME=%s %s' % (_CROS_GSUTIL_HOME_WAR, _GSUTIL_PATH)
50 if util.IsRunningOnCrosDevice(): 47 return ('To configure your credentials:\n'
51 gsutil_path = ('HOME=%s %s' % (_CROS_GSUTIL_HOME_WAR, gsutil_path)) 48 ' 1. Run "%s config" and follow its instructions.\n'
52 return ('To configure your credentials:\n' 49 ' 2. If you have a @google.com account, use that account.\n'
53 ' 1. Run "%s config" and follow its instructions.\n' 50 ' 3. For the project-id, just enter 0.' % command)
54 ' 2. If you have a @google.com account, use that account.\n'
55 ' 3. For the project-id, just enter 0.' % gsutil_path)
56 51
57 52
58 class PermissionError(CloudStorageError): 53 class PermissionError(CloudStorageError):
59 def __init__(self, gsutil_path): 54 def __init__(self):
60 super(PermissionError, self).__init__( 55 super(PermissionError, self).__init__(
61 'Attempted to access a file from Cloud Storage but you don\'t ' 56 'Attempted to access a file from Cloud Storage but you don\'t '
62 'have permission. ' + self._GetConfigInstructions(gsutil_path)) 57 'have permission. ' + self._GetConfigInstructions())
63 58
64 59
65 class CredentialsError(CloudStorageError): 60 class CredentialsError(CloudStorageError):
66 def __init__(self, gsutil_path): 61 def __init__(self):
67 super(CredentialsError, self).__init__( 62 super(CredentialsError, self).__init__(
68 'Attempted to access a file from Cloud Storage but you have no ' 63 'Attempted to access a file from Cloud Storage but you have no '
69 'configured credentials. ' + self._GetConfigInstructions(gsutil_path)) 64 'configured credentials. ' + self._GetConfigInstructions())
70 65
71 66
72 class NotFoundError(CloudStorageError): 67 class NotFoundError(CloudStorageError):
73 pass 68 pass
74 69
75 70
76 class ServerError(CloudStorageError): 71 class ServerError(CloudStorageError):
77 pass 72 pass
78 73
79 74
80 # TODO(tonyg/dtu): Can this be replaced with distutils.spawn.find_executable()? 75 # TODO(tonyg/dtu): Can this be replaced with distutils.spawn.find_executable()?
81 def _FindExecutableInPath(relative_executable_path, *extra_search_paths): 76 def _FindExecutableInPath(relative_executable_path, *extra_search_paths):
82 search_paths = list(extra_search_paths) + os.environ['PATH'].split(os.pathsep) 77 search_paths = list(extra_search_paths) + os.environ['PATH'].split(os.pathsep)
83 for search_path in search_paths: 78 for search_path in search_paths:
84 executable_path = os.path.join(search_path, relative_executable_path) 79 executable_path = os.path.join(search_path, relative_executable_path)
85 if path.IsExecutable(executable_path): 80 if path.IsExecutable(executable_path):
86 return executable_path 81 return executable_path
87 return None 82 return None
88 83
89 84
90 def _DownloadGsutil():
91 logging.info('Downloading gsutil')
92 with contextlib.closing(urllib2.urlopen(_GSUTIL_URL, timeout=60)) as response:
93 with tarfile.open(fileobj=cStringIO.StringIO(response.read())) as tar_file:
94 tar_file.extractall(os.path.dirname(_DOWNLOAD_PATH))
95 logging.info('Downloaded gsutil to %s' % _DOWNLOAD_PATH)
96
97 return os.path.join(_DOWNLOAD_PATH, 'gsutil')
98
99
100 def FindGsutil():
101 """Return the gsutil executable path. If we can't find it, download it."""
102 # Look for a depot_tools installation.
103 # FIXME: gsutil in depot_tools is not working correctly. crbug.com/413414
104 #gsutil_path = _FindExecutableInPath(
105 # os.path.join('third_party', 'gsutil', 'gsutil'), _DOWNLOAD_PATH)
106 #if gsutil_path:
107 # return gsutil_path
108
109 # Look for a gsutil installation.
110 gsutil_path = _FindExecutableInPath('gsutil', _DOWNLOAD_PATH)
111 if gsutil_path:
112 return gsutil_path
113
114 # Failed to find it. Download it!
115 return _DownloadGsutil()
116
117
118 def SupportsProdaccess(gsutil_path):
nednguyen 2015/07/29 18:01:19 I delete this because this code doesn't make any s
aiolos (Not reviewing) 2015/07/29 23:22:27 I *think* this is fine to remove at this point, bu
aiolos (Not reviewing) 2015/07/29 23:26:29 It might make more sense to do this in a separate
nednguyen 2015/08/01 04:16:17 Done.
119 with open(gsutil_path, 'r') as gsutil:
120 return 'prodaccess' in gsutil.read()
121
122
123 def _RunCommand(args): 85 def _RunCommand(args):
124 gsutil_path = FindGsutil()
125
126 # On cros device, as telemetry is running as root, home will be set to /root/, 86 # On cros device, as telemetry is running as root, home will be set to /root/,
127 # which is not writable. gsutil will attempt to create a download tracker dir 87 # which is not writable. gsutil will attempt to create a download tracker dir
128 # in home dir and fail. To avoid this, override HOME dir to something writable 88 # in home dir and fail. To avoid this, override HOME dir to something writable
129 # when running on cros device. 89 # when running on cros device.
130 # 90 #
131 # TODO(tbarzic): Figure out a better way to handle gsutil on cros. 91 # TODO(tbarzic): Figure out a better way to handle gsutil on cros.
132 # http://crbug.com/386416, http://crbug.com/359293. 92 # http://crbug.com/386416, http://crbug.com/359293.
133 gsutil_env = None 93 gsutil_env = None
134 if util.IsRunningOnCrosDevice(): 94 if util.IsRunningOnCrosDevice():
135 gsutil_env = os.environ.copy() 95 gsutil_env = os.environ.copy()
136 gsutil_env['HOME'] = _CROS_GSUTIL_HOME_WAR 96 gsutil_env['HOME'] = _CROS_GSUTIL_HOME_WAR
137 97
138 if os.name == 'nt': 98 if os.name == 'nt':
139 # If Windows, prepend python. Python scripts aren't directly executable. 99 # If Windows, prepend python. Python scripts aren't directly executable.
140 args = [sys.executable, gsutil_path] + args 100 args = [sys.executable, _GSUTIL_PATH] + args
141 else: 101 else:
142 # Don't do it on POSIX, in case someone is using a shell script to redirect. 102 # Don't do it on POSIX, in case someone is using a shell script to redirect.
143 args = [gsutil_path] + args 103 args = [_GSUTIL_PATH] + args
144 104
145 gsutil = subprocess.Popen(args, stdout=subprocess.PIPE, 105 gsutil = subprocess.Popen(args, stdout=subprocess.PIPE,
146 stderr=subprocess.PIPE, env=gsutil_env) 106 stderr=subprocess.PIPE, env=gsutil_env)
147 stdout, stderr = gsutil.communicate() 107 stdout, stderr = gsutil.communicate()
148 108
149 if gsutil.returncode: 109 if gsutil.returncode:
150 if stderr.startswith(( 110 if stderr.startswith((
151 'You are attempting to access protected data with no configured', 111 'You are attempting to access protected data with no configured',
152 'Failure: No handler was ready to authenticate.')): 112 'Failure: No handler was ready to authenticate.')):
153 raise CredentialsError(gsutil_path) 113 raise CredentialsError()
154 if ('status=403' in stderr or 'status 403' in stderr or 114 if ('status=403' in stderr or 'status 403' in stderr or
155 '403 Forbidden' in stderr): 115 '403 Forbidden' in stderr):
156 raise PermissionError(gsutil_path) 116 raise PermissionError()
157 if (stderr.startswith('InvalidUriError') or 'No such object' in stderr or 117 if (stderr.startswith('InvalidUriError') or 'No such object' in stderr or
158 'No URLs matched' in stderr or 'One or more URLs matched no' in stderr): 118 'No URLs matched' in stderr or 'One or more URLs matched no' in stderr):
159 raise NotFoundError(stderr) 119 raise NotFoundError(stderr)
160 if '500 Internal Server Error' in stderr: 120 if '500 Internal Server Error' in stderr:
161 raise ServerError(stderr) 121 raise ServerError(stderr)
162 raise CloudStorageError(stderr) 122 raise CloudStorageError(stderr)
163 123
164 return stdout 124 return stdout
165 125
166 126
(...skipping 129 matching lines...) Expand 10 before | Expand all | Expand 10 after
296 chunk = f.read(1024*1024) 256 chunk = f.read(1024*1024)
297 if not chunk: 257 if not chunk:
298 break 258 break
299 sha1.update(chunk) 259 sha1.update(chunk)
300 return sha1.hexdigest() 260 return sha1.hexdigest()
301 261
302 262
303 def ReadHash(hash_path): 263 def ReadHash(hash_path):
304 with open(hash_path, 'rb') as f: 264 with open(hash_path, 'rb') as f:
305 return f.read(1024).rstrip() 265 return f.read(1024).rstrip()
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698