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

Side by Side Diff: third_party/boto/gs/bucket.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/gs/acl.py ('k') | third_party/boto/gs/bucketlistresultset.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 2010 Google Inc.
2 #
3 # Permission is hereby granted, free of charge, to any person obtaining a
4 # copy of this software and associated documentation files (the
5 # "Software"), to deal in the Software without restriction, including
6 # without limitation the rights to use, copy, modify, merge, publish, dis-
7 # tribute, sublicense, and/or sell copies of the Software, and to permit
8 # persons to whom the Software is furnished to do so, subject to the fol-
9 # lowing conditions:
10 #
11 # The above copyright notice and this permission notice shall be included
12 # in all copies or substantial portions of the Software.
13 #
14 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15 # OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL-
16 # ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
17 # SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
18 # WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
20 # IN THE SOFTWARE.
21
22 import urllib
23 import xml.sax
24
25 import boto
26 from boto import handler
27 from boto.resultset import ResultSet
28 from boto.exception import InvalidAclError
29 from boto.gs.acl import ACL, CannedACLStrings
30 from boto.gs.acl import SupportedPermissions as GSPermissions
31 from boto.gs.bucketlistresultset import VersionedBucketListResultSet
32 from boto.gs.cors import Cors
33 from boto.gs.key import Key as GSKey
34 from boto.s3.acl import Policy
35 from boto.s3.bucket import Bucket as S3Bucket
36
37 # constants for http query args
38 DEF_OBJ_ACL = 'defaultObjectAcl'
39 STANDARD_ACL = 'acl'
40 CORS_ARG = 'cors'
41
42 class Bucket(S3Bucket):
43 """Represents a Google Cloud Storage bucket."""
44
45 VersioningBody = ('<?xml version="1.0" encoding="UTF-8"?>\n'
46 '<VersioningConfiguration><Status>%s</Status>'
47 '</VersioningConfiguration>')
48 WebsiteBody = ('<?xml version="1.0" encoding="UTF-8"?>\n'
49 '<WebsiteConfiguration>%s%s</WebsiteConfiguration>')
50 WebsiteMainPageFragment = '<MainPageSuffix>%s</MainPageSuffix>'
51 WebsiteErrorFragment = '<NotFoundPage>%s</NotFoundPage>'
52
53 def __init__(self, connection=None, name=None, key_class=GSKey):
54 super(Bucket, self).__init__(connection, name, key_class)
55
56 def startElement(self, name, attrs, connection):
57 return None
58
59 def endElement(self, name, value, connection):
60 if name == 'Name':
61 self.name = value
62 elif name == 'CreationDate':
63 self.creation_date = value
64 else:
65 setattr(self, name, value)
66
67 def get_key(self, key_name, headers=None, version_id=None,
68 response_headers=None, generation=None):
69 """Returns a Key instance for an object in this bucket.
70
71 Note that this method uses a HEAD request to check for the existence of
72 the key.
73
74 :type key_name: string
75 :param key_name: The name of the key to retrieve
76
77 :type response_headers: dict
78 :param response_headers: A dictionary containing HTTP
79 headers/values that will override any headers associated
80 with the stored object in the response. See
81 http://goo.gl/06N3b for details.
82
83 :type version_id: string
84 :param version_id: Unused in this subclass.
85
86 :type generation: int
87 :param generation: A specific generation number to fetch the key at. If
88 not specified, the latest generation is fetched.
89
90 :rtype: :class:`boto.gs.key.Key`
91 :returns: A Key object from this bucket.
92 """
93 query_args_l = []
94 if generation:
95 query_args_l.append('generation=%s' % generation)
96 if response_headers:
97 for rk, rv in response_headers.iteritems():
98 query_args_l.append('%s=%s' % (rk, urllib.quote(rv)))
99
100 key, resp = self._get_key_internal(key_name, headers,
101 query_args_l=query_args_l)
102 return key
103
104 def copy_key(self, new_key_name, src_bucket_name, src_key_name,
105 metadata=None, src_version_id=None, storage_class='STANDARD',
106 preserve_acl=False, encrypt_key=False, headers=None,
107 query_args=None, src_generation=None):
108 """Create a new key in the bucket by copying an existing key.
109
110 :type new_key_name: string
111 :param new_key_name: The name of the new key
112
113 :type src_bucket_name: string
114 :param src_bucket_name: The name of the source bucket
115
116 :type src_key_name: string
117 :param src_key_name: The name of the source key
118
119 :type src_generation: int
120 :param src_generation: The generation number of the source key to copy.
121 If not specified, the latest generation is copied.
122
123 :type metadata: dict
124 :param metadata: Metadata to be associated with new key. If
125 metadata is supplied, it will replace the metadata of the
126 source key being copied. If no metadata is supplied, the
127 source key's metadata will be copied to the new key.
128
129 :type version_id: string
130 :param version_id: Unused in this subclass.
131
132 :type storage_class: string
133 :param storage_class: The storage class of the new key. By
134 default, the new key will use the standard storage class.
135 Possible values are: STANDARD | DURABLE_REDUCED_AVAILABILITY
136
137 :type preserve_acl: bool
138 :param preserve_acl: If True, the ACL from the source key will
139 be copied to the destination key. If False, the
140 destination key will have the default ACL. Note that
141 preserving the ACL in the new key object will require two
142 additional API calls to GCS, one to retrieve the current
143 ACL and one to set that ACL on the new object. If you
144 don't care about the ACL (or if you have a default ACL set
145 on the bucket), a value of False will be significantly more
146 efficient.
147
148 :type encrypt_key: bool
149 :param encrypt_key: Included for compatibility with S3. This argument is
150 ignored.
151
152 :type headers: dict
153 :param headers: A dictionary of header name/value pairs.
154
155 :type query_args: string
156 :param query_args: A string of additional querystring arguments
157 to append to the request
158
159 :rtype: :class:`boto.gs.key.Key`
160 :returns: An instance of the newly created key object
161 """
162 if src_generation:
163 headers = headers or {}
164 headers['x-goog-copy-source-generation'] = str(src_generation)
165 return super(Bucket, self).copy_key(
166 new_key_name, src_bucket_name, src_key_name, metadata=metadata,
167 storage_class=storage_class, preserve_acl=preserve_acl,
168 encrypt_key=encrypt_key, headers=headers, query_args=query_args)
169
170 def list_versions(self, prefix='', delimiter='', marker='',
171 generation_marker='', headers=None):
172 """
173 List versioned objects within a bucket. This returns an
174 instance of an VersionedBucketListResultSet that automatically
175 handles all of the result paging, etc. from GCS. You just need
176 to keep iterating until there are no more results. Called
177 with no arguments, this will return an iterator object across
178 all keys within the bucket.
179
180 :type prefix: string
181 :param prefix: allows you to limit the listing to a particular
182 prefix. For example, if you call the method with
183 prefix='/foo/' then the iterator will only cycle through
184 the keys that begin with the string '/foo/'.
185
186 :type delimiter: string
187 :param delimiter: can be used in conjunction with the prefix
188 to allow you to organize and browse your keys
189 hierarchically. See:
190 https://developers.google.com/storage/docs/reference-headers#delimit er
191 for more details.
192
193 :type marker: string
194 :param marker: The "marker" of where you are in the result set
195
196 :type generation_marker: string
197 :param generation_marker: The "generation marker" of where you are in
198 the result set.
199
200 :type headers: dict
201 :param headers: A dictionary of header name/value pairs.
202
203 :rtype:
204 :class:`boto.gs.bucketlistresultset.VersionedBucketListResultSet`
205 :return: an instance of a BucketListResultSet that handles paging, etc.
206 """
207 return VersionedBucketListResultSet(self, prefix, delimiter,
208 marker, generation_marker,
209 headers)
210
211 def delete_key(self, key_name, headers=None, version_id=None,
212 mfa_token=None, generation=None):
213 """
214 Deletes a key from the bucket.
215
216 :type key_name: string
217 :param key_name: The key name to delete
218
219 :type headers: dict
220 :param headers: A dictionary of header name/value pairs.
221
222 :type version_id: string
223 :param version_id: Unused in this subclass.
224
225 :type mfa_token: tuple or list of strings
226 :param mfa_token: Unused in this subclass.
227
228 :type generation: int
229 :param generation: The generation number of the key to delete. If not
230 specified, the latest generation number will be deleted.
231
232 :rtype: :class:`boto.gs.key.Key`
233 :returns: A key object holding information on what was
234 deleted.
235 """
236 query_args_l = []
237 if generation:
238 query_args_l.append('generation=%s' % generation)
239 self._delete_key_internal(key_name, headers=headers,
240 version_id=version_id, mfa_token=mfa_token,
241 query_args_l=query_args_l)
242
243 def set_acl(self, acl_or_str, key_name='', headers=None, version_id=None,
244 generation=None, if_generation=None, if_metageneration=None):
245 """Sets or changes a bucket's or key's ACL.
246
247 :type acl_or_str: string or :class:`boto.gs.acl.ACL`
248 :param acl_or_str: A canned ACL string (see
249 :data:`~.gs.acl.CannedACLStrings`) or an ACL object.
250
251 :type key_name: string
252 :param key_name: A key name within the bucket to set the ACL for. If not
253 specified, the ACL for the bucket will be set.
254
255 :type headers: dict
256 :param headers: Additional headers to set during the request.
257
258 :type version_id: string
259 :param version_id: Unused in this subclass.
260
261 :type generation: int
262 :param generation: If specified, sets the ACL for a specific generation
263 of a versioned object. If not specified, the current version is
264 modified.
265
266 :type if_generation: int
267 :param if_generation: (optional) If set to a generation number, the acl
268 will only be updated if its current generation number is this value.
269
270 :type if_metageneration: int
271 :param if_metageneration: (optional) If set to a metageneration number,
272 the acl will only be updated if its current metageneration number is
273 this value.
274 """
275 if isinstance(acl_or_str, Policy):
276 raise InvalidAclError('Attempt to set S3 Policy on GS ACL')
277 elif isinstance(acl_or_str, ACL):
278 self.set_xml_acl(acl_or_str.to_xml(), key_name, headers=headers,
279 generation=generation,
280 if_generation=if_generation,
281 if_metageneration=if_metageneration)
282 else:
283 self.set_canned_acl(acl_or_str, key_name, headers=headers,
284 generation=generation,
285 if_generation=if_generation,
286 if_metageneration=if_metageneration)
287
288 def set_def_acl(self, acl_or_str, headers=None):
289 """Sets or changes a bucket's default ACL.
290
291 :type acl_or_str: string or :class:`boto.gs.acl.ACL`
292 :param acl_or_str: A canned ACL string (see
293 :data:`~.gs.acl.CannedACLStrings`) or an ACL object.
294
295 :type headers: dict
296 :param headers: Additional headers to set during the request.
297 """
298 if isinstance(acl_or_str, Policy):
299 raise InvalidAclError('Attempt to set S3 Policy on GS ACL')
300 elif isinstance(acl_or_str, ACL):
301 self.set_def_xml_acl(acl_or_str.to_xml(), headers=headers)
302 else:
303 self.set_def_canned_acl(acl_or_str, headers=headers)
304
305 def _get_xml_acl_helper(self, key_name, headers, query_args):
306 """Provides common functionality for get_xml_acl and _get_acl_helper."""
307 response = self.connection.make_request('GET', self.name, key_name,
308 query_args=query_args,
309 headers=headers)
310 body = response.read()
311 if response.status != 200:
312 raise self.connection.provider.storage_response_error(
313 response.status, response.reason, body)
314 return body
315
316 def _get_acl_helper(self, key_name, headers, query_args):
317 """Provides common functionality for get_acl and get_def_acl."""
318 body = self._get_xml_acl_helper(key_name, headers, query_args)
319 acl = ACL(self)
320 h = handler.XmlHandler(acl, self)
321 xml.sax.parseString(body, h)
322 return acl
323
324 def get_acl(self, key_name='', headers=None, version_id=None,
325 generation=None):
326 """Returns the ACL of the bucket or an object in the bucket.
327
328 :param str key_name: The name of the object to get the ACL for. If not
329 specified, the ACL for the bucket will be returned.
330
331 :param dict headers: Additional headers to set during the request.
332
333 :type version_id: string
334 :param version_id: Unused in this subclass.
335
336 :param int generation: If specified, gets the ACL for a specific
337 generation of a versioned object. If not specified, the current
338 version is returned. This parameter is only valid when retrieving
339 the ACL of an object, not a bucket.
340
341 :rtype: :class:`.gs.acl.ACL`
342 """
343 query_args = STANDARD_ACL
344 if generation:
345 query_args += '&generation=%s' % generation
346 return self._get_acl_helper(key_name, headers, query_args)
347
348 def get_xml_acl(self, key_name='', headers=None, version_id=None,
349 generation=None):
350 """Returns the ACL string of the bucket or an object in the bucket.
351
352 :param str key_name: The name of the object to get the ACL for. If not
353 specified, the ACL for the bucket will be returned.
354
355 :param dict headers: Additional headers to set during the request.
356
357 :type version_id: string
358 :param version_id: Unused in this subclass.
359
360 :param int generation: If specified, gets the ACL for a specific
361 generation of a versioned object. If not specified, the current
362 version is returned. This parameter is only valid when retrieving
363 the ACL of an object, not a bucket.
364
365 :rtype: str
366 """
367 query_args = STANDARD_ACL
368 if generation:
369 query_args += '&generation=%s' % generation
370 return self._get_xml_acl_helper(key_name, headers, query_args)
371
372 def get_def_acl(self, headers=None):
373 """Returns the bucket's default ACL.
374
375 :param dict headers: Additional headers to set during the request.
376
377 :rtype: :class:`.gs.acl.ACL`
378 """
379 return self._get_acl_helper('', headers, DEF_OBJ_ACL)
380
381 def _set_acl_helper(self, acl_or_str, key_name, headers, query_args,
382 generation, if_generation, if_metageneration,
383 canned=False):
384 """Provides common functionality for set_acl, set_xml_acl,
385 set_canned_acl, set_def_acl, set_def_xml_acl, and
386 set_def_canned_acl()."""
387
388 headers = headers or {}
389 data = ''
390 if canned:
391 headers[self.connection.provider.acl_header] = acl_or_str
392 else:
393 data = acl_or_str.encode('UTF-8')
394
395 if generation:
396 query_args += '&generation=%s' % generation
397
398 if if_metageneration is not None and if_generation is None:
399 raise ValueError("Received if_metageneration argument with no "
400 "if_generation argument. A meta-generation has no "
401 "meaning without a content generation.")
402 if not key_name and (if_generation or if_metageneration):
403 raise ValueError("Received if_generation or if_metageneration "
404 "parameter while setting the ACL of a bucket.")
405 if if_generation is not None:
406 headers['x-goog-if-generation-match'] = str(if_generation)
407 if if_metageneration is not None:
408 headers['x-goog-if-metageneration-match'] = str(if_metageneration)
409
410 response = self.connection.make_request('PUT', self.name, key_name,
411 data=data, headers=headers, query_args=query_args)
412 body = response.read()
413 if response.status != 200:
414 raise self.connection.provider.storage_response_error(
415 response.status, response.reason, body)
416
417 def set_xml_acl(self, acl_str, key_name='', headers=None, version_id=None,
418 query_args='acl', generation=None, if_generation=None,
419 if_metageneration=None):
420 """Sets a bucket's or objects's ACL to an XML string.
421
422 :type acl_str: string
423 :param acl_str: A string containing the ACL XML.
424
425 :type key_name: string
426 :param key_name: A key name within the bucket to set the ACL for. If not
427 specified, the ACL for the bucket will be set.
428
429 :type headers: dict
430 :param headers: Additional headers to set during the request.
431
432 :type version_id: string
433 :param version_id: Unused in this subclass.
434
435 :type query_args: str
436 :param query_args: The query parameters to pass with the request.
437
438 :type generation: int
439 :param generation: If specified, sets the ACL for a specific generation
440 of a versioned object. If not specified, the current version is
441 modified.
442
443 :type if_generation: int
444 :param if_generation: (optional) If set to a generation number, the acl
445 will only be updated if its current generation number is this value.
446
447 :type if_metageneration: int
448 :param if_metageneration: (optional) If set to a metageneration number,
449 the acl will only be updated if its current metageneration number is
450 this value.
451 """
452 return self._set_acl_helper(acl_str, key_name=key_name, headers=headers,
453 query_args=query_args,
454 generation=generation,
455 if_generation=if_generation,
456 if_metageneration=if_metageneration)
457
458 def set_canned_acl(self, acl_str, key_name='', headers=None,
459 version_id=None, generation=None, if_generation=None,
460 if_metageneration=None):
461 """Sets a bucket's or objects's ACL using a predefined (canned) value.
462
463 :type acl_str: string
464 :param acl_str: A canned ACL string. See
465 :data:`~.gs.acl.CannedACLStrings`.
466
467 :type key_name: string
468 :param key_name: A key name within the bucket to set the ACL for. If not
469 specified, the ACL for the bucket will be set.
470
471 :type headers: dict
472 :param headers: Additional headers to set during the request.
473
474 :type version_id: string
475 :param version_id: Unused in this subclass.
476
477 :type generation: int
478 :param generation: If specified, sets the ACL for a specific generation
479 of a versioned object. If not specified, the current version is
480 modified.
481
482 :type if_generation: int
483 :param if_generation: (optional) If set to a generation number, the acl
484 will only be updated if its current generation number is this value.
485
486 :type if_metageneration: int
487 :param if_metageneration: (optional) If set to a metageneration number,
488 the acl will only be updated if its current metageneration number is
489 this value.
490 """
491 if acl_str not in CannedACLStrings:
492 raise ValueError("Provided canned ACL string (%s) is not valid."
493 % acl_str)
494 query_args = STANDARD_ACL
495 return self._set_acl_helper(acl_str, key_name, headers, query_args,
496 generation, if_generation,
497 if_metageneration, canned=True)
498
499 def set_def_canned_acl(self, acl_str, headers=None):
500 """Sets a bucket's default ACL using a predefined (canned) value.
501
502 :type acl_str: string
503 :param acl_str: A canned ACL string. See
504 :data:`~.gs.acl.CannedACLStrings`.
505
506 :type headers: dict
507 :param headers: Additional headers to set during the request.
508 """
509 if acl_str not in CannedACLStrings:
510 raise ValueError("Provided canned ACL string (%s) is not valid."
511 % acl_str)
512 query_args = DEF_OBJ_ACL
513 return self._set_acl_helper(acl_str, '', headers, query_args,
514 generation=None, if_generation=None,
515 if_metageneration=None, canned=True)
516
517 def set_def_xml_acl(self, acl_str, headers=None):
518 """Sets a bucket's default ACL to an XML string.
519
520 :type acl_str: string
521 :param acl_str: A string containing the ACL XML.
522
523 :type headers: dict
524 :param headers: Additional headers to set during the request.
525 """
526 return self.set_xml_acl(acl_str, '', headers,
527 query_args=DEF_OBJ_ACL)
528
529 def get_cors(self, headers=None):
530 """Returns a bucket's CORS XML document.
531
532 :param dict headers: Additional headers to send with the request.
533 :rtype: :class:`~.cors.Cors`
534 """
535 response = self.connection.make_request('GET', self.name,
536 query_args=CORS_ARG,
537 headers=headers)
538 body = response.read()
539 if response.status == 200:
540 # Success - parse XML and return Cors object.
541 cors = Cors()
542 h = handler.XmlHandler(cors, self)
543 xml.sax.parseString(body, h)
544 return cors
545 else:
546 raise self.connection.provider.storage_response_error(
547 response.status, response.reason, body)
548
549 def set_cors(self, cors, headers=None):
550 """Sets a bucket's CORS XML document.
551
552 :param str cors: A string containing the CORS XML.
553 :param dict headers: Additional headers to send with the request.
554 """
555 cors_xml = cors.encode('UTF-8')
556 response = self.connection.make_request('PUT', self.name,
557 data=cors_xml,
558 query_args=CORS_ARG,
559 headers=headers)
560 body = response.read()
561 if response.status != 200:
562 raise self.connection.provider.storage_response_error(
563 response.status, response.reason, body)
564
565 def get_storage_class(self):
566 """
567 Returns the StorageClass for the bucket.
568
569 :rtype: str
570 :return: The StorageClass for the bucket.
571 """
572 response = self.connection.make_request('GET', self.name,
573 query_args='storageClass')
574 body = response.read()
575 if response.status == 200:
576 rs = ResultSet(self)
577 h = handler.XmlHandler(rs, self)
578 xml.sax.parseString(body, h)
579 return rs.StorageClass
580 else:
581 raise self.connection.provider.storage_response_error(
582 response.status, response.reason, body)
583
584
585 # Method with same signature as boto.s3.bucket.Bucket.add_email_grant(),
586 # to allow polymorphic treatment at application layer.
587 def add_email_grant(self, permission, email_address,
588 recursive=False, headers=None):
589 """
590 Convenience method that provides a quick way to add an email grant
591 to a bucket. This method retrieves the current ACL, creates a new
592 grant based on the parameters passed in, adds that grant to the ACL
593 and then PUT's the new ACL back to GCS.
594
595 :type permission: string
596 :param permission: The permission being granted. Should be one of:
597 (READ, WRITE, FULL_CONTROL).
598
599 :type email_address: string
600 :param email_address: The email address associated with the GS
601 account your are granting the permission to.
602
603 :type recursive: bool
604 :param recursive: A boolean value to controls whether the call
605 will apply the grant to all keys within the bucket
606 or not. The default value is False. By passing a
607 True value, the call will iterate through all keys
608 in the bucket and apply the same grant to each key.
609 CAUTION: If you have a lot of keys, this could take
610 a long time!
611 """
612 if permission not in GSPermissions:
613 raise self.connection.provider.storage_permissions_error(
614 'Unknown Permission: %s' % permission)
615 acl = self.get_acl(headers=headers)
616 acl.add_email_grant(permission, email_address)
617 self.set_acl(acl, headers=headers)
618 if recursive:
619 for key in self:
620 key.add_email_grant(permission, email_address, headers=headers)
621
622 # Method with same signature as boto.s3.bucket.Bucket.add_user_grant(),
623 # to allow polymorphic treatment at application layer.
624 def add_user_grant(self, permission, user_id, recursive=False,
625 headers=None):
626 """
627 Convenience method that provides a quick way to add a canonical user
628 grant to a bucket. This method retrieves the current ACL, creates a new
629 grant based on the parameters passed in, adds that grant to the ACL and
630 then PUTs the new ACL back to GCS.
631
632 :type permission: string
633 :param permission: The permission being granted. Should be one of:
634 (READ|WRITE|FULL_CONTROL)
635
636 :type user_id: string
637 :param user_id: The canonical user id associated with the GS account
638 you are granting the permission to.
639
640 :type recursive: bool
641 :param recursive: A boolean value to controls whether the call
642 will apply the grant to all keys within the bucket
643 or not. The default value is False. By passing a
644 True value, the call will iterate through all keys
645 in the bucket and apply the same grant to each key.
646 CAUTION: If you have a lot of keys, this could take
647 a long time!
648 """
649 if permission not in GSPermissions:
650 raise self.connection.provider.storage_permissions_error(
651 'Unknown Permission: %s' % permission)
652 acl = self.get_acl(headers=headers)
653 acl.add_user_grant(permission, user_id)
654 self.set_acl(acl, headers=headers)
655 if recursive:
656 for key in self:
657 key.add_user_grant(permission, user_id, headers=headers)
658
659 def add_group_email_grant(self, permission, email_address, recursive=False,
660 headers=None):
661 """
662 Convenience method that provides a quick way to add an email group
663 grant to a bucket. This method retrieves the current ACL, creates a new
664 grant based on the parameters passed in, adds that grant to the ACL and
665 then PUT's the new ACL back to GCS.
666
667 :type permission: string
668 :param permission: The permission being granted. Should be one of:
669 READ|WRITE|FULL_CONTROL
670 See http://code.google.com/apis/storage/docs/developer-guide.html#au thorization
671 for more details on permissions.
672
673 :type email_address: string
674 :param email_address: The email address associated with the Google
675 Group to which you are granting the permission.
676
677 :type recursive: bool
678 :param recursive: A boolean value to controls whether the call
679 will apply the grant to all keys within the bucket
680 or not. The default value is False. By passing a
681 True value, the call will iterate through all keys
682 in the bucket and apply the same grant to each key.
683 CAUTION: If you have a lot of keys, this could take
684 a long time!
685 """
686 if permission not in GSPermissions:
687 raise self.connection.provider.storage_permissions_error(
688 'Unknown Permission: %s' % permission)
689 acl = self.get_acl(headers=headers)
690 acl.add_group_email_grant(permission, email_address)
691 self.set_acl(acl, headers=headers)
692 if recursive:
693 for key in self:
694 key.add_group_email_grant(permission, email_address,
695 headers=headers)
696
697 # Method with same input signature as boto.s3.bucket.Bucket.list_grants()
698 # (but returning different object type), to allow polymorphic treatment
699 # at application layer.
700 def list_grants(self, headers=None):
701 """Returns the ACL entries applied to this bucket.
702
703 :param dict headers: Additional headers to send with the request.
704 :rtype: list containing :class:`~.gs.acl.Entry` objects.
705 """
706 acl = self.get_acl(headers=headers)
707 return acl.entries
708
709 def disable_logging(self, headers=None):
710 """Disable logging on this bucket.
711
712 :param dict headers: Additional headers to send with the request.
713 """
714 xml_str = '<?xml version="1.0" encoding="UTF-8"?><Logging/>'
715 self.set_subresource('logging', xml_str, headers=headers)
716
717 def enable_logging(self, target_bucket, target_prefix=None, headers=None):
718 """Enable logging on a bucket.
719
720 :type target_bucket: bucket or string
721 :param target_bucket: The bucket to log to.
722
723 :type target_prefix: string
724 :param target_prefix: The prefix which should be prepended to the
725 generated log files written to the target_bucket.
726
727 :param dict headers: Additional headers to send with the request.
728 """
729 if isinstance(target_bucket, Bucket):
730 target_bucket = target_bucket.name
731 xml_str = '<?xml version="1.0" encoding="UTF-8"?><Logging>'
732 xml_str = (xml_str + '<LogBucket>%s</LogBucket>' % target_bucket)
733 if target_prefix:
734 xml_str = (xml_str +
735 '<LogObjectPrefix>%s</LogObjectPrefix>' % target_prefix)
736 xml_str = xml_str + '</Logging>'
737
738 self.set_subresource('logging', xml_str, headers=headers)
739
740 def configure_website(self, main_page_suffix=None, error_key=None,
741 headers=None):
742 """Configure this bucket to act as a website
743
744 :type main_page_suffix: str
745 :param main_page_suffix: Suffix that is appended to a request that is
746 for a "directory" on the website endpoint (e.g. if the suffix is
747 index.html and you make a request to samplebucket/images/ the data
748 that is returned will be for the object with the key name
749 images/index.html). The suffix must not be empty and must not
750 include a slash character. This parameter is optional and the
751 property is disabled if excluded.
752
753 :type error_key: str
754 :param error_key: The object key name to use when a 400 error occurs.
755 This parameter is optional and the property is disabled if excluded.
756
757 :param dict headers: Additional headers to send with the request.
758 """
759 if main_page_suffix:
760 main_page_frag = self.WebsiteMainPageFragment % main_page_suffix
761 else:
762 main_page_frag = ''
763
764 if error_key:
765 error_frag = self.WebsiteErrorFragment % error_key
766 else:
767 error_frag = ''
768
769 body = self.WebsiteBody % (main_page_frag, error_frag)
770 response = self.connection.make_request('PUT', self.name, data=body,
771 query_args='websiteConfig',
772 headers=headers)
773 body = response.read()
774 if response.status == 200:
775 return True
776 else:
777 raise self.connection.provider.storage_response_error(
778 response.status, response.reason, body)
779
780 def get_website_configuration(self, headers=None):
781 """Returns the current status of website configuration on the bucket.
782
783 :param dict headers: Additional headers to send with the request.
784
785 :rtype: dict
786 :returns: A dictionary containing a Python representation
787 of the XML response from GCS. The overall structure is:
788
789 * WebsiteConfiguration
790
791 * MainPageSuffix: suffix that is appended to request that
792 is for a "directory" on the website endpoint.
793 * NotFoundPage: name of an object to serve when site visitors
794 encounter a 404.
795 """
796 return self.get_website_configuration_xml(self, headers)[0]
797
798 def get_website_configuration_with_xml(self, headers=None):
799 """Returns the current status of website configuration on the bucket as
800 unparsed XML.
801
802 :param dict headers: Additional headers to send with the request.
803
804 :rtype: 2-Tuple
805 :returns: 2-tuple containing:
806
807 1) A dictionary containing a Python representation of the XML
808 response from GCS. The overall structure is:
809
810 * WebsiteConfiguration
811
812 * MainPageSuffix: suffix that is appended to request that is for
813 a "directory" on the website endpoint.
814 * NotFoundPage: name of an object to serve when site visitors
815 encounter a 404
816
817 2) Unparsed XML describing the bucket's website configuration.
818 """
819 response = self.connection.make_request('GET', self.name,
820 query_args='websiteConfig', headers=headers)
821 body = response.read()
822 boto.log.debug(body)
823
824 if response.status != 200:
825 raise self.connection.provider.storage_response_error(
826 response.status, response.reason, body)
827
828 e = boto.jsonresponse.Element()
829 h = boto.jsonresponse.XmlHandler(e, None)
830 h.parse(body)
831 return e, body
832
833 def delete_website_configuration(self, headers=None):
834 """Remove the website configuration from this bucket.
835
836 :param dict headers: Additional headers to send with the request.
837 """
838 self.configure_website(headers=headers)
839
840 def get_versioning_status(self, headers=None):
841 """Returns the current status of versioning configuration on the bucket.
842
843 :rtype: bool
844 """
845 response = self.connection.make_request('GET', self.name,
846 query_args='versioning',
847 headers=headers)
848 body = response.read()
849 boto.log.debug(body)
850 if response.status != 200:
851 raise self.connection.provider.storage_response_error(
852 response.status, response.reason, body)
853 resp_json = boto.jsonresponse.Element()
854 boto.jsonresponse.XmlHandler(resp_json, None).parse(body)
855 resp_json = resp_json['VersioningConfiguration']
856 return ('Status' in resp_json) and (resp_json['Status'] == 'Enabled')
857
858 def configure_versioning(self, enabled, headers=None):
859 """Configure versioning for this bucket.
860
861 :param bool enabled: If set to True, enables versioning on this bucket.
862 If set to False, disables versioning.
863
864 :param dict headers: Additional headers to send with the request.
865 """
866 if enabled == True:
867 req_body = self.VersioningBody % ('Enabled')
868 else:
869 req_body = self.VersioningBody % ('Suspended')
870 self.set_subresource('versioning', req_body, headers=headers)
OLDNEW
« no previous file with comments | « third_party/boto/gs/acl.py ('k') | third_party/boto/gs/bucketlistresultset.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698