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

Side by Side Diff: third_party/gsutil/boto/provider.py

Issue 12042069: Scripts to download files from google storage based on sha1 sums (Closed) Base URL: https://chromium.googlesource.com/chromium/tools/depot_tools.git@master
Patch Set: Removed gsutil/tests and gsutil/docs Created 7 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
OLDNEW
(Empty)
1 # Copyright (c) 2010 Mitch Garnaat http://garnaat.org/
2 # Copyright 2010 Google Inc.
3 # Copyright (c) 2010, Eucalyptus Systems, Inc.
4 # Copyright (c) 2011, Nexenta Systems Inc.
5 # All rights reserved.
6 #
7 # Permission is hereby granted, free of charge, to any person obtaining a
8 # copy of this software and associated documentation files (the
9 # "Software"), to deal in the Software without restriction, including
10 # without limitation the rights to use, copy, modify, merge, publish, dis-
11 # tribute, sublicense, and/or sell copies of the Software, and to permit
12 # persons to whom the Software is furnished to do so, subject to the fol-
13 # lowing conditions:
14 #
15 # The above copyright notice and this permission notice shall be included
16 # in all copies or substantial portions of the Software.
17 #
18 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19 # OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL-
20 # ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
21 # SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
22 # WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
24 # IN THE SOFTWARE.
25 """
26 This class encapsulates the provider-specific header differences.
27 """
28
29 import os
30 from datetime import datetime
31
32 import boto
33 from boto import config
34 from boto.gs.acl import ACL
35 from boto.gs.acl import CannedACLStrings as CannedGSACLStrings
36 from boto.s3.acl import CannedACLStrings as CannedS3ACLStrings
37 from boto.s3.acl import Policy
38
39
40 HEADER_PREFIX_KEY = 'header_prefix'
41 METADATA_PREFIX_KEY = 'metadata_prefix'
42
43 AWS_HEADER_PREFIX = 'x-amz-'
44 GOOG_HEADER_PREFIX = 'x-goog-'
45
46 ACL_HEADER_KEY = 'acl-header'
47 AUTH_HEADER_KEY = 'auth-header'
48 COPY_SOURCE_HEADER_KEY = 'copy-source-header'
49 COPY_SOURCE_VERSION_ID_HEADER_KEY = 'copy-source-version-id-header'
50 COPY_SOURCE_RANGE_HEADER_KEY = 'copy-source-range-header'
51 DELETE_MARKER_HEADER_KEY = 'delete-marker-header'
52 DATE_HEADER_KEY = 'date-header'
53 METADATA_DIRECTIVE_HEADER_KEY = 'metadata-directive-header'
54 RESUMABLE_UPLOAD_HEADER_KEY = 'resumable-upload-header'
55 SECURITY_TOKEN_HEADER_KEY = 'security-token-header'
56 STORAGE_CLASS_HEADER_KEY = 'storage-class'
57 MFA_HEADER_KEY = 'mfa-header'
58 SERVER_SIDE_ENCRYPTION_KEY = 'server-side-encryption-header'
59 VERSION_ID_HEADER_KEY = 'version-id-header'
60
61 STORAGE_COPY_ERROR = 'StorageCopyError'
62 STORAGE_CREATE_ERROR = 'StorageCreateError'
63 STORAGE_DATA_ERROR = 'StorageDataError'
64 STORAGE_PERMISSIONS_ERROR = 'StoragePermissionsError'
65 STORAGE_RESPONSE_ERROR = 'StorageResponseError'
66
67
68 class Provider(object):
69
70 CredentialMap = {
71 'aws': ('aws_access_key_id', 'aws_secret_access_key'),
72 'google': ('gs_access_key_id', 'gs_secret_access_key'),
73 }
74
75 AclClassMap = {
76 'aws': Policy,
77 'google': ACL
78 }
79
80 CannedAclsMap = {
81 'aws': CannedS3ACLStrings,
82 'google': CannedGSACLStrings
83 }
84
85 HostKeyMap = {
86 'aws': 's3',
87 'google': 'gs'
88 }
89
90 ChunkedTransferSupport = {
91 'aws': False,
92 'google': True
93 }
94
95 MetadataServiceSupport = {
96 'aws': True,
97 'google': False
98 }
99
100 # If you update this map please make sure to put "None" for the
101 # right-hand-side for any headers that don't apply to a provider, rather
102 # than simply leaving that header out (which would cause KeyErrors).
103 HeaderInfoMap = {
104 'aws': {
105 HEADER_PREFIX_KEY: AWS_HEADER_PREFIX,
106 METADATA_PREFIX_KEY: AWS_HEADER_PREFIX + 'meta-',
107 ACL_HEADER_KEY: AWS_HEADER_PREFIX + 'acl',
108 AUTH_HEADER_KEY: 'AWS',
109 COPY_SOURCE_HEADER_KEY: AWS_HEADER_PREFIX + 'copy-source',
110 COPY_SOURCE_VERSION_ID_HEADER_KEY: AWS_HEADER_PREFIX +
111 'copy-source-version-id',
112 COPY_SOURCE_RANGE_HEADER_KEY: AWS_HEADER_PREFIX +
113 'copy-source-range',
114 DATE_HEADER_KEY: AWS_HEADER_PREFIX + 'date',
115 DELETE_MARKER_HEADER_KEY: AWS_HEADER_PREFIX + 'delete-marker',
116 METADATA_DIRECTIVE_HEADER_KEY: AWS_HEADER_PREFIX +
117 'metadata-directive',
118 RESUMABLE_UPLOAD_HEADER_KEY: None,
119 SECURITY_TOKEN_HEADER_KEY: AWS_HEADER_PREFIX + 'security-token',
120 SERVER_SIDE_ENCRYPTION_KEY: AWS_HEADER_PREFIX + 'server-side-encrypt ion',
121 VERSION_ID_HEADER_KEY: AWS_HEADER_PREFIX + 'version-id',
122 STORAGE_CLASS_HEADER_KEY: AWS_HEADER_PREFIX + 'storage-class',
123 MFA_HEADER_KEY: AWS_HEADER_PREFIX + 'mfa',
124 },
125 'google': {
126 HEADER_PREFIX_KEY: GOOG_HEADER_PREFIX,
127 METADATA_PREFIX_KEY: GOOG_HEADER_PREFIX + 'meta-',
128 ACL_HEADER_KEY: GOOG_HEADER_PREFIX + 'acl',
129 AUTH_HEADER_KEY: 'GOOG1',
130 COPY_SOURCE_HEADER_KEY: GOOG_HEADER_PREFIX + 'copy-source',
131 COPY_SOURCE_VERSION_ID_HEADER_KEY: GOOG_HEADER_PREFIX +
132 'copy-source-version-id',
133 COPY_SOURCE_RANGE_HEADER_KEY: None,
134 DATE_HEADER_KEY: GOOG_HEADER_PREFIX + 'date',
135 DELETE_MARKER_HEADER_KEY: GOOG_HEADER_PREFIX + 'delete-marker',
136 METADATA_DIRECTIVE_HEADER_KEY: GOOG_HEADER_PREFIX +
137 'metadata-directive',
138 RESUMABLE_UPLOAD_HEADER_KEY: GOOG_HEADER_PREFIX + 'resumable',
139 SECURITY_TOKEN_HEADER_KEY: GOOG_HEADER_PREFIX + 'security-token',
140 SERVER_SIDE_ENCRYPTION_KEY: None,
141 # Note that this version header is not to be confused with
142 # the Google Cloud Storage 'x-goog-api-version' header.
143 VERSION_ID_HEADER_KEY: GOOG_HEADER_PREFIX + 'version-id',
144 STORAGE_CLASS_HEADER_KEY: None,
145 MFA_HEADER_KEY: None,
146 }
147 }
148
149 ErrorMap = {
150 'aws': {
151 STORAGE_COPY_ERROR: boto.exception.S3CopyError,
152 STORAGE_CREATE_ERROR: boto.exception.S3CreateError,
153 STORAGE_DATA_ERROR: boto.exception.S3DataError,
154 STORAGE_PERMISSIONS_ERROR: boto.exception.S3PermissionsError,
155 STORAGE_RESPONSE_ERROR: boto.exception.S3ResponseError,
156 },
157 'google': {
158 STORAGE_COPY_ERROR: boto.exception.GSCopyError,
159 STORAGE_CREATE_ERROR: boto.exception.GSCreateError,
160 STORAGE_DATA_ERROR: boto.exception.GSDataError,
161 STORAGE_PERMISSIONS_ERROR: boto.exception.GSPermissionsError,
162 STORAGE_RESPONSE_ERROR: boto.exception.GSResponseError,
163 }
164 }
165
166 def __init__(self, name, access_key=None, secret_key=None,
167 security_token=None):
168 self.host = None
169 self.access_key = access_key
170 self.secret_key = secret_key
171 self.security_token = security_token
172 self.name = name
173 self.acl_class = self.AclClassMap[self.name]
174 self.canned_acls = self.CannedAclsMap[self.name]
175 self._credential_expiry_time = None
176 self.get_credentials(access_key, secret_key)
177 self.configure_headers()
178 self.configure_errors()
179 # allow config file to override default host
180 host_opt_name = '%s_host' % self.HostKeyMap[self.name]
181 if config.has_option('Credentials', host_opt_name):
182 self.host = config.get('Credentials', host_opt_name)
183
184 def get_access_key(self):
185 if self._credentials_need_refresh():
186 self._populate_keys_from_metadata_server()
187 return self._access_key
188
189 def set_access_key(self, value):
190 self._access_key = value
191
192 access_key = property(get_access_key, set_access_key)
193
194 def get_secret_key(self):
195 if self._credentials_need_refresh():
196 self._populate_keys_from_metadata_server()
197 return self._secret_key
198
199 def set_secret_key(self, value):
200 self._secret_key = value
201
202 secret_key = property(get_secret_key, set_secret_key)
203
204 def get_security_token(self):
205 if self._credentials_need_refresh():
206 self._populate_keys_from_metadata_server()
207 return self._security_token
208
209 def set_security_token(self, value):
210 self._security_token = value
211
212 security_token = property(get_security_token, set_security_token)
213
214 def _credentials_need_refresh(self):
215 if self._credential_expiry_time is None:
216 return False
217 else:
218 # The credentials should be refreshed if they're going to expire
219 # in less than 5 minutes.
220 delta = self._credential_expiry_time - datetime.utcnow()
221 # python2.6 does not have timedelta.total_seconds() so we have
222 # to calculate this ourselves. This is straight from the
223 # datetime docs.
224 seconds_left = (
225 (delta.microseconds + (delta.seconds + delta.days * 24 * 3600)
226 * 10**6) / 10**6)
227 if seconds_left < (5 * 60):
228 boto.log.debug("Credentials need to be refreshed.")
229 return True
230 else:
231 return False
232
233
234 def get_credentials(self, access_key=None, secret_key=None):
235 access_key_name, secret_key_name = self.CredentialMap[self.name]
236 if access_key is not None:
237 self.access_key = access_key
238 elif access_key_name.upper() in os.environ:
239 self.access_key = os.environ[access_key_name.upper()]
240 elif config.has_option('Credentials', access_key_name):
241 self.access_key = config.get('Credentials', access_key_name)
242
243 if secret_key is not None:
244 self.secret_key = secret_key
245 elif secret_key_name.upper() in os.environ:
246 self.secret_key = os.environ[secret_key_name.upper()]
247 elif config.has_option('Credentials', secret_key_name):
248 self.secret_key = config.get('Credentials', secret_key_name)
249
250 if ((self._access_key is None or self._secret_key is None) and
251 self.MetadataServiceSupport[self.name]):
252 self._populate_keys_from_metadata_server()
253 self._secret_key = self._convert_key_to_str(self._secret_key)
254
255 def _populate_keys_from_metadata_server(self):
256 # get_instance_metadata is imported here because of a circular
257 # dependency.
258 boto.log.debug("Retrieving credentials from metadata server.")
259 from boto.utils import get_instance_metadata
260 timeout = config.getfloat('Boto', 'metadata_service_timeout', 1.0)
261 metadata = get_instance_metadata(timeout=timeout, num_retries=1)
262 # I'm assuming there's only one role on the instance profile.
263 if metadata and 'iam' in metadata:
264 security = metadata['iam']['security-credentials'].values()[0]
265 self._access_key = security['AccessKeyId']
266 self._secret_key = self._convert_key_to_str(security['SecretAccessKe y'])
267 self._security_token = security['Token']
268 expires_at = security['Expiration']
269 self._credential_expiry_time = datetime.strptime(
270 expires_at, "%Y-%m-%dT%H:%M:%SZ")
271 boto.log.debug("Retrieved credentials will expire in %s at: %s",
272 self._credential_expiry_time - datetime.now(), expire s_at)
273
274 def _convert_key_to_str(self, key):
275 if isinstance(key, unicode):
276 # the secret key must be bytes and not unicode to work
277 # properly with hmac.new (see http://bugs.python.org/issue5285)
278 return str(key)
279 return key
280
281 def configure_headers(self):
282 header_info_map = self.HeaderInfoMap[self.name]
283 self.metadata_prefix = header_info_map[METADATA_PREFIX_KEY]
284 self.header_prefix = header_info_map[HEADER_PREFIX_KEY]
285 self.acl_header = header_info_map[ACL_HEADER_KEY]
286 self.auth_header = header_info_map[AUTH_HEADER_KEY]
287 self.copy_source_header = header_info_map[COPY_SOURCE_HEADER_KEY]
288 self.copy_source_version_id = header_info_map[
289 COPY_SOURCE_VERSION_ID_HEADER_KEY]
290 self.copy_source_range_header = header_info_map[
291 COPY_SOURCE_RANGE_HEADER_KEY]
292 self.date_header = header_info_map[DATE_HEADER_KEY]
293 self.delete_marker = header_info_map[DELETE_MARKER_HEADER_KEY]
294 self.metadata_directive_header = (
295 header_info_map[METADATA_DIRECTIVE_HEADER_KEY])
296 self.security_token_header = header_info_map[SECURITY_TOKEN_HEADER_KEY]
297 self.resumable_upload_header = (
298 header_info_map[RESUMABLE_UPLOAD_HEADER_KEY])
299 self.server_side_encryption_header = header_info_map[SERVER_SIDE_ENCRYPT ION_KEY]
300 self.storage_class_header = header_info_map[STORAGE_CLASS_HEADER_KEY]
301 self.version_id = header_info_map[VERSION_ID_HEADER_KEY]
302 self.mfa_header = header_info_map[MFA_HEADER_KEY]
303
304 def configure_errors(self):
305 error_map = self.ErrorMap[self.name]
306 self.storage_copy_error = error_map[STORAGE_COPY_ERROR]
307 self.storage_create_error = error_map[STORAGE_CREATE_ERROR]
308 self.storage_data_error = error_map[STORAGE_DATA_ERROR]
309 self.storage_permissions_error = error_map[STORAGE_PERMISSIONS_ERROR]
310 self.storage_response_error = error_map[STORAGE_RESPONSE_ERROR]
311
312 def get_provider_name(self):
313 return self.HostKeyMap[self.name]
314
315 def supports_chunked_transfer(self):
316 return self.ChunkedTransferSupport[self.name]
317
318 # Static utility method for getting default Provider.
319 def get_default():
320 return Provider('aws')
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698