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

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: Fix unittest 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 | tools/telemetry/catapult_base/cloud_storage_unittest.py » ('j') | 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', 'gsutilz',
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():
44 command = _GSUTIL_PATH
47 if util.IsRunningOnCrosDevice(): 45 if util.IsRunningOnCrosDevice():
48 gsutil_path = ('HOME=%s %s' % (_CROS_GSUTIL_HOME_WAR, gsutil_path)) 46 command = 'HOME=%s %s' % (_CROS_GSUTIL_HOME_WAR, _GSUTIL_PATH)
49 return ('To configure your credentials:\n' 47 return ('To configure your credentials:\n'
50 ' 1. Run "%s config" and follow its instructions.\n' 48 ' 1. Run "%s config" and follow its instructions.\n'
51 ' 2. If you have a @google.com account, use that account.\n' 49 ' 2. If you have a @google.com account, use that account.\n'
52 ' 3. For the project-id, just enter 0.' % gsutil_path) 50 ' 3. For the project-id, just enter 0.' % command)
53 51
54 52
55 class PermissionError(CloudStorageError): 53 class PermissionError(CloudStorageError):
56 def __init__(self, gsutil_path): 54 def __init__(self):
57 super(PermissionError, self).__init__( 55 super(PermissionError, self).__init__(
58 '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 '
59 'have permission. ' + self._GetConfigInstructions(gsutil_path)) 57 'have permission. ' + self._GetConfigInstructions())
60 58
61 59
62 class CredentialsError(CloudStorageError): 60 class CredentialsError(CloudStorageError):
63 def __init__(self, gsutil_path): 61 def __init__(self):
64 super(CredentialsError, self).__init__( 62 super(CredentialsError, self).__init__(
65 '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 '
66 'configured credentials. ' + self._GetConfigInstructions(gsutil_path)) 64 'configured credentials. ' + self._GetConfigInstructions())
67 65
68 66
69 class NotFoundError(CloudStorageError): 67 class NotFoundError(CloudStorageError):
70 pass 68 pass
71 69
72 70
73 class ServerError(CloudStorageError): 71 class ServerError(CloudStorageError):
74 pass 72 pass
75 73
76 74
77 # 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()?
78 def _FindExecutableInPath(relative_executable_path, *extra_search_paths): 76 def _FindExecutableInPath(relative_executable_path, *extra_search_paths):
79 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)
80 for search_path in search_paths: 78 for search_path in search_paths:
81 executable_path = os.path.join(search_path, relative_executable_path) 79 executable_path = os.path.join(search_path, relative_executable_path)
82 if path.IsExecutable(executable_path): 80 if path.IsExecutable(executable_path):
83 return executable_path 81 return executable_path
84 return None 82 return None
85 83
86 84
87 def _DownloadGsutil():
88 logging.info('Downloading gsutil')
89 with contextlib.closing(urllib2.urlopen(_GSUTIL_URL, timeout=60)) as response:
90 with tarfile.open(fileobj=cStringIO.StringIO(response.read())) as tar_file:
91 tar_file.extractall(os.path.dirname(_DOWNLOAD_PATH))
92 logging.info('Downloaded gsutil to %s' % _DOWNLOAD_PATH)
93
94 return os.path.join(_DOWNLOAD_PATH, 'gsutil')
95
96
97 def FindGsutil():
98 """Return the gsutil executable path. If we can't find it, download it."""
99 # Look for a depot_tools installation.
100 # FIXME: gsutil in depot_tools is not working correctly. crbug.com/413414
101 #gsutil_path = _FindExecutableInPath(
102 # os.path.join('third_party', 'gsutil', 'gsutil'), _DOWNLOAD_PATH)
103 #if gsutil_path:
104 # return gsutil_path
105
106 # Look for a gsutil installation.
107 gsutil_path = _FindExecutableInPath('gsutil', _DOWNLOAD_PATH)
108 if gsutil_path:
109 return gsutil_path
110
111 # Failed to find it. Download it!
112 return _DownloadGsutil()
113
114
115 def _RunCommand(args): 85 def _RunCommand(args):
116 gsutil_path = FindGsutil()
117
118 # 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/,
119 # 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
120 # 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
121 # when running on cros device. 89 # when running on cros device.
122 # 90 #
123 # 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.
124 # http://crbug.com/386416, http://crbug.com/359293. 92 # http://crbug.com/386416, http://crbug.com/359293.
125 gsutil_env = None 93 gsutil_env = None
126 if util.IsRunningOnCrosDevice(): 94 if util.IsRunningOnCrosDevice():
127 gsutil_env = os.environ.copy() 95 gsutil_env = os.environ.copy()
128 gsutil_env['HOME'] = _CROS_GSUTIL_HOME_WAR 96 gsutil_env['HOME'] = _CROS_GSUTIL_HOME_WAR
129 97
130 if os.name == 'nt': 98 if os.name == 'nt':
131 # If Windows, prepend python. Python scripts aren't directly executable. 99 # If Windows, prepend python. Python scripts aren't directly executable.
132 args = [sys.executable, gsutil_path] + args 100 args = [sys.executable, _GSUTIL_PATH] + args
133 else: 101 else:
134 # 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.
135 args = [gsutil_path] + args 103 args = [_GSUTIL_PATH] + args
136 104
137 gsutil = subprocess.Popen(args, stdout=subprocess.PIPE, 105 gsutil = subprocess.Popen(args, stdout=subprocess.PIPE,
138 stderr=subprocess.PIPE, env=gsutil_env) 106 stderr=subprocess.PIPE, env=gsutil_env)
139 stdout, stderr = gsutil.communicate() 107 stdout, stderr = gsutil.communicate()
140 108
141 if gsutil.returncode: 109 if gsutil.returncode:
142 if stderr.startswith(( 110 if stderr.startswith((
143 'You are attempting to access protected data with no configured', 111 'You are attempting to access protected data with no configured',
144 'Failure: No handler was ready to authenticate.')): 112 'Failure: No handler was ready to authenticate.')):
145 raise CredentialsError(gsutil_path) 113 raise CredentialsError()
146 if ('status=403' in stderr or 'status 403' in stderr or 114 if ('status=403' in stderr or 'status 403' in stderr or
147 '403 Forbidden' in stderr): 115 '403 Forbidden' in stderr):
148 raise PermissionError(gsutil_path) 116 raise PermissionError()
149 if (stderr.startswith('InvalidUriError') or 'No such object' in stderr or 117 if (stderr.startswith('InvalidUriError') or 'No such object' in stderr or
150 '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):
151 raise NotFoundError(stderr) 119 raise NotFoundError(stderr)
152 if '500 Internal Server Error' in stderr: 120 if '500 Internal Server Error' in stderr:
153 raise ServerError(stderr) 121 raise ServerError(stderr)
154 raise CloudStorageError(stderr) 122 raise CloudStorageError(stderr)
155 123
156 return stdout 124 return stdout
157 125
158 126
(...skipping 129 matching lines...) Expand 10 before | Expand all | Expand 10 after
288 chunk = f.read(1024*1024) 256 chunk = f.read(1024*1024)
289 if not chunk: 257 if not chunk:
290 break 258 break
291 sha1.update(chunk) 259 sha1.update(chunk)
292 return sha1.hexdigest() 260 return sha1.hexdigest()
293 261
294 262
295 def ReadHash(hash_path): 263 def ReadHash(hash_path):
296 with open(hash_path, 'rb') as f: 264 with open(hash_path, 'rb') as f:
297 return f.read(1024).rstrip() 265 return f.read(1024).rstrip()
OLDNEW
« no previous file with comments | « no previous file | tools/telemetry/catapult_base/cloud_storage_unittest.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698