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

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

Issue 12633019: Added boto/ to depot_tools/third_party (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/tools/depot_tools
Patch Set: Moved boto down by one Created 7 years, 9 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 | Annotate | Revision Log
« no previous file with comments | « third_party/boto/plugin.py ('k') | third_party/boto/pyami/__init__.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 (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 def get_credentials(self, access_key=None, secret_key=None):
234 access_key_name, secret_key_name = self.CredentialMap[self.name]
235 if access_key is not None:
236 self.access_key = access_key
237 boto.log.debug("Using access key provided by client.")
238 elif access_key_name.upper() in os.environ:
239 self.access_key = os.environ[access_key_name.upper()]
240 boto.log.debug("Using access key found in environment variable.")
241 elif config.has_option('Credentials', access_key_name):
242 self.access_key = config.get('Credentials', access_key_name)
243 boto.log.debug("Using access key found in config file.")
244
245 if secret_key is not None:
246 self.secret_key = secret_key
247 boto.log.debug("Using secret key provided by client.")
248 elif secret_key_name.upper() in os.environ:
249 self.secret_key = os.environ[secret_key_name.upper()]
250 boto.log.debug("Using secret key found in environment variable.")
251 elif config.has_option('Credentials', secret_key_name):
252 self.secret_key = config.get('Credentials', secret_key_name)
253 boto.log.debug("Using secret key found in config file.")
254 elif config.has_option('Credentials', 'keyring'):
255 keyring_name = config.get('Credentials', 'keyring')
256 try:
257 import keyring
258 except ImportError:
259 boto.log.error("The keyring module could not be imported. "
260 "For keyring support, install the keyring "
261 "module.")
262 raise
263 self.secret_key = keyring.get_password(
264 keyring_name, self.access_key)
265 boto.log.debug("Using secret key found in keyring.")
266
267 if ((self._access_key is None or self._secret_key is None) and
268 self.MetadataServiceSupport[self.name]):
269 self._populate_keys_from_metadata_server()
270 self._secret_key = self._convert_key_to_str(self._secret_key)
271
272 def _populate_keys_from_metadata_server(self):
273 # get_instance_metadata is imported here because of a circular
274 # dependency.
275 boto.log.debug("Retrieving credentials from metadata server.")
276 from boto.utils import get_instance_metadata
277 timeout = config.getfloat('Boto', 'metadata_service_timeout', 1.0)
278 metadata = get_instance_metadata(timeout=timeout, num_retries=1)
279 # I'm assuming there's only one role on the instance profile.
280 if metadata and 'iam' in metadata:
281 security = metadata['iam']['security-credentials'].values()[0]
282 self._access_key = security['AccessKeyId']
283 self._secret_key = self._convert_key_to_str(security['SecretAccessKe y'])
284 self._security_token = security['Token']
285 expires_at = security['Expiration']
286 self._credential_expiry_time = datetime.strptime(
287 expires_at, "%Y-%m-%dT%H:%M:%SZ")
288 boto.log.debug("Retrieved credentials will expire in %s at: %s",
289 self._credential_expiry_time - datetime.now(), expire s_at)
290
291 def _convert_key_to_str(self, key):
292 if isinstance(key, unicode):
293 # the secret key must be bytes and not unicode to work
294 # properly with hmac.new (see http://bugs.python.org/issue5285)
295 return str(key)
296 return key
297
298 def configure_headers(self):
299 header_info_map = self.HeaderInfoMap[self.name]
300 self.metadata_prefix = header_info_map[METADATA_PREFIX_KEY]
301 self.header_prefix = header_info_map[HEADER_PREFIX_KEY]
302 self.acl_header = header_info_map[ACL_HEADER_KEY]
303 self.auth_header = header_info_map[AUTH_HEADER_KEY]
304 self.copy_source_header = header_info_map[COPY_SOURCE_HEADER_KEY]
305 self.copy_source_version_id = header_info_map[
306 COPY_SOURCE_VERSION_ID_HEADER_KEY]
307 self.copy_source_range_header = header_info_map[
308 COPY_SOURCE_RANGE_HEADER_KEY]
309 self.date_header = header_info_map[DATE_HEADER_KEY]
310 self.delete_marker = header_info_map[DELETE_MARKER_HEADER_KEY]
311 self.metadata_directive_header = (
312 header_info_map[METADATA_DIRECTIVE_HEADER_KEY])
313 self.security_token_header = header_info_map[SECURITY_TOKEN_HEADER_KEY]
314 self.resumable_upload_header = (
315 header_info_map[RESUMABLE_UPLOAD_HEADER_KEY])
316 self.server_side_encryption_header = header_info_map[SERVER_SIDE_ENCRYPT ION_KEY]
317 self.storage_class_header = header_info_map[STORAGE_CLASS_HEADER_KEY]
318 self.version_id = header_info_map[VERSION_ID_HEADER_KEY]
319 self.mfa_header = header_info_map[MFA_HEADER_KEY]
320
321 def configure_errors(self):
322 error_map = self.ErrorMap[self.name]
323 self.storage_copy_error = error_map[STORAGE_COPY_ERROR]
324 self.storage_create_error = error_map[STORAGE_CREATE_ERROR]
325 self.storage_data_error = error_map[STORAGE_DATA_ERROR]
326 self.storage_permissions_error = error_map[STORAGE_PERMISSIONS_ERROR]
327 self.storage_response_error = error_map[STORAGE_RESPONSE_ERROR]
328
329 def get_provider_name(self):
330 return self.HostKeyMap[self.name]
331
332 def supports_chunked_transfer(self):
333 return self.ChunkedTransferSupport[self.name]
334
335 # Static utility method for getting default Provider.
336 def get_default():
337 return Provider('aws')
OLDNEW
« no previous file with comments | « third_party/boto/plugin.py ('k') | third_party/boto/pyami/__init__.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698