Mercurial > repos > shellac > guppy_basecaller
diff env/lib/python3.7/site-packages/boto/gs/bucket.py @ 5:9b1c78e6ba9c draft default tip
"planemo upload commit 6c0a8142489327ece472c84e558c47da711a9142"
author | shellac |
---|---|
date | Mon, 01 Jun 2020 08:59:25 -0400 |
parents | 79f47841a781 |
children |
line wrap: on
line diff
--- a/env/lib/python3.7/site-packages/boto/gs/bucket.py Thu May 14 16:47:39 2020 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1134 +0,0 @@ -# Copyright 2010 Google Inc. -# -# Permission is hereby granted, free of charge, to any person obtaining a -# copy of this software and associated documentation files (the -# "Software"), to deal in the Software without restriction, including -# without limitation the rights to use, copy, modify, merge, publish, dis- -# tribute, sublicense, and/or sell copies of the Software, and to permit -# persons to whom the Software is furnished to do so, subject to the fol- -# lowing conditions: -# -# The above copyright notice and this permission notice shall be included -# in all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL- -# ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT -# SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -# IN THE SOFTWARE. - -import re -import urllib -import xml.sax - -import boto -from boto import handler -from boto.resultset import ResultSet -from boto.exception import GSResponseError -from boto.exception import InvalidAclError -from boto.gs.acl import ACL, CannedACLStrings -from boto.gs.acl import SupportedPermissions as GSPermissions -from boto.gs.bucketlistresultset import VersionedBucketListResultSet -from boto.gs.cors import Cors -from boto.gs.encryptionconfig import EncryptionConfig -from boto.gs.lifecycle import LifecycleConfig -from boto.gs.key import Key as GSKey -from boto.s3.acl import Policy -from boto.s3.bucket import Bucket as S3Bucket -from boto.utils import get_utf8_value -from boto.compat import six - -# constants for http query args -DEF_OBJ_ACL = 'defaultObjectAcl' -STANDARD_ACL = 'acl' -CORS_ARG = 'cors' -ENCRYPTION_CONFIG_ARG = 'encryptionConfig' -LIFECYCLE_ARG = 'lifecycle' -STORAGE_CLASS_ARG='storageClass' -ERROR_DETAILS_REGEX = re.compile(r'<Details>(?P<details>.*)</Details>') - -class Bucket(S3Bucket): - """Represents a Google Cloud Storage bucket.""" - - BillingBody = ('<?xml version="1.0" encoding="UTF-8"?>\n' - '<BillingConfiguration>' - '<RequesterPays>%s</RequesterPays>' - '</BillingConfiguration>') - EncryptionConfigBody = ( - '<?xml version="1.0" encoding="UTF-8"?>\n' - '<EncryptionConfiguration>%s</EncryptionConfiguration>') - EncryptionConfigDefaultKeyNameFragment = ( - '<DefaultKmsKeyName>%s</DefaultKmsKeyName>') - StorageClassBody = ('<?xml version="1.0" encoding="UTF-8"?>\n' - '<StorageClass>%s</StorageClass>') - VersioningBody = ('<?xml version="1.0" encoding="UTF-8"?>\n' - '<VersioningConfiguration>' - '<Status>%s</Status>' - '</VersioningConfiguration>') - WebsiteBody = ('<?xml version="1.0" encoding="UTF-8"?>\n' - '<WebsiteConfiguration>%s%s</WebsiteConfiguration>') - WebsiteMainPageFragment = '<MainPageSuffix>%s</MainPageSuffix>' - WebsiteErrorFragment = '<NotFoundPage>%s</NotFoundPage>' - - def __init__(self, connection=None, name=None, key_class=GSKey): - super(Bucket, self).__init__(connection, name, key_class) - - def startElement(self, name, attrs, connection): - return None - - def endElement(self, name, value, connection): - if name == 'Name': - self.name = value - elif name == 'CreationDate': - self.creation_date = value - else: - setattr(self, name, value) - - def get_key(self, key_name, headers=None, version_id=None, - response_headers=None, generation=None): - """Returns a Key instance for an object in this bucket. - - Note that this method uses a HEAD request to check for the existence of - the key. - - :type key_name: string - :param key_name: The name of the key to retrieve - - :type response_headers: dict - :param response_headers: A dictionary containing HTTP - headers/values that will override any headers associated - with the stored object in the response. See - http://goo.gl/06N3b for details. - - :type version_id: string - :param version_id: Unused in this subclass. - - :type generation: int - :param generation: A specific generation number to fetch the key at. If - not specified, the latest generation is fetched. - - :rtype: :class:`boto.gs.key.Key` - :returns: A Key object from this bucket. - """ - query_args_l = [] - if generation: - query_args_l.append('generation=%s' % generation) - if response_headers: - for rk, rv in six.iteritems(response_headers): - query_args_l.append('%s=%s' % (rk, urllib.quote(rv))) - try: - key, resp = self._get_key_internal(key_name, headers, - query_args_l=query_args_l) - except GSResponseError as e: - if e.status == 403 and 'Forbidden' in e.reason: - # If we failed getting an object, let the user know which object - # failed rather than just returning a generic 403. - e.reason = ("Access denied to 'gs://%s/%s'." % - (self.name, key_name)) - raise - return key - - def copy_key(self, new_key_name, src_bucket_name, src_key_name, - metadata=None, src_version_id=None, storage_class='STANDARD', - preserve_acl=False, encrypt_key=False, headers=None, - query_args=None, src_generation=None): - """Create a new key in the bucket by copying an existing key. - - :type new_key_name: string - :param new_key_name: The name of the new key - - :type src_bucket_name: string - :param src_bucket_name: The name of the source bucket - - :type src_key_name: string - :param src_key_name: The name of the source key - - :type src_generation: int - :param src_generation: The generation number of the source key to copy. - If not specified, the latest generation is copied. - - :type metadata: dict - :param metadata: Metadata to be associated with new key. If - metadata is supplied, it will replace the metadata of the - source key being copied. If no metadata is supplied, the - source key's metadata will be copied to the new key. - - :type version_id: string - :param version_id: Unused in this subclass. - - :type storage_class: string - :param storage_class: The storage class of the new key. By - default, the new key will use the standard storage class. - Possible values are: STANDARD | DURABLE_REDUCED_AVAILABILITY - - :type preserve_acl: bool - :param preserve_acl: If True, the ACL from the source key will - be copied to the destination key. If False, the - destination key will have the default ACL. Note that - preserving the ACL in the new key object will require two - additional API calls to GCS, one to retrieve the current - ACL and one to set that ACL on the new object. If you - don't care about the ACL (or if you have a default ACL set - on the bucket), a value of False will be significantly more - efficient. - - :type encrypt_key: bool - :param encrypt_key: Included for compatibility with S3. This argument is - ignored. - - :type headers: dict - :param headers: A dictionary of header name/value pairs. - - :type query_args: string - :param query_args: A string of additional querystring arguments - to append to the request - - :rtype: :class:`boto.gs.key.Key` - :returns: An instance of the newly created key object - """ - if src_generation: - headers = headers or {} - headers['x-goog-copy-source-generation'] = str(src_generation) - return super(Bucket, self).copy_key( - new_key_name, src_bucket_name, src_key_name, metadata=metadata, - storage_class=storage_class, preserve_acl=preserve_acl, - encrypt_key=encrypt_key, headers=headers, query_args=query_args) - - def list_versions(self, prefix='', delimiter='', marker='', - generation_marker='', headers=None): - """ - List versioned objects within a bucket. This returns an - instance of an VersionedBucketListResultSet that automatically - handles all of the result paging, etc. from GCS. You just need - to keep iterating until there are no more results. Called - with no arguments, this will return an iterator object across - all keys within the bucket. - - :type prefix: string - :param prefix: allows you to limit the listing to a particular - prefix. For example, if you call the method with - prefix='/foo/' then the iterator will only cycle through - the keys that begin with the string '/foo/'. - - :type delimiter: string - :param delimiter: can be used in conjunction with the prefix - to allow you to organize and browse your keys - hierarchically. See: - https://developers.google.com/storage/docs/reference-headers#delimiter - for more details. - - :type marker: string - :param marker: The "marker" of where you are in the result set - - :type generation_marker: string - :param generation_marker: The "generation marker" of where you are in - the result set. - - :type headers: dict - :param headers: A dictionary of header name/value pairs. - - :rtype: - :class:`boto.gs.bucketlistresultset.VersionedBucketListResultSet` - :return: an instance of a BucketListResultSet that handles paging, etc. - """ - return VersionedBucketListResultSet(self, prefix, delimiter, - marker, generation_marker, - headers) - - def validate_get_all_versions_params(self, params): - """ - See documentation in boto/s3/bucket.py. - """ - self.validate_kwarg_names(params, - ['version_id_marker', 'delimiter', 'marker', - 'generation_marker', 'prefix', 'max_keys']) - - def delete_key(self, key_name, headers=None, version_id=None, - mfa_token=None, generation=None): - """ - Deletes a key from the bucket. - - :type key_name: string - :param key_name: The key name to delete - - :type headers: dict - :param headers: A dictionary of header name/value pairs. - - :type version_id: string - :param version_id: Unused in this subclass. - - :type mfa_token: tuple or list of strings - :param mfa_token: Unused in this subclass. - - :type generation: int - :param generation: The generation number of the key to delete. If not - specified, the latest generation number will be deleted. - - :rtype: :class:`boto.gs.key.Key` - :returns: A key object holding information on what was - deleted. - """ - query_args_l = [] - if generation: - query_args_l.append('generation=%s' % generation) - self._delete_key_internal(key_name, headers=headers, - version_id=version_id, mfa_token=mfa_token, - query_args_l=query_args_l) - - def set_acl(self, acl_or_str, key_name='', headers=None, version_id=None, - generation=None, if_generation=None, if_metageneration=None): - """Sets or changes a bucket's or key's ACL. - - :type acl_or_str: string or :class:`boto.gs.acl.ACL` - :param acl_or_str: A canned ACL string (see - :data:`~.gs.acl.CannedACLStrings`) or an ACL object. - - :type key_name: string - :param key_name: A key name within the bucket to set the ACL for. If not - specified, the ACL for the bucket will be set. - - :type headers: dict - :param headers: Additional headers to set during the request. - - :type version_id: string - :param version_id: Unused in this subclass. - - :type generation: int - :param generation: If specified, sets the ACL for a specific generation - of a versioned object. If not specified, the current version is - modified. - - :type if_generation: int - :param if_generation: (optional) If set to a generation number, the acl - will only be updated if its current generation number is this value. - - :type if_metageneration: int - :param if_metageneration: (optional) If set to a metageneration number, - the acl will only be updated if its current metageneration number is - this value. - """ - if isinstance(acl_or_str, Policy): - raise InvalidAclError('Attempt to set S3 Policy on GS ACL') - elif isinstance(acl_or_str, ACL): - self.set_xml_acl(acl_or_str.to_xml(), key_name, headers=headers, - generation=generation, - if_generation=if_generation, - if_metageneration=if_metageneration) - else: - self.set_canned_acl(acl_or_str, key_name, headers=headers, - generation=generation, - if_generation=if_generation, - if_metageneration=if_metageneration) - - def set_def_acl(self, acl_or_str, headers=None): - """Sets or changes a bucket's default ACL. - - :type acl_or_str: string or :class:`boto.gs.acl.ACL` - :param acl_or_str: A canned ACL string (see - :data:`~.gs.acl.CannedACLStrings`) or an ACL object. - - :type headers: dict - :param headers: Additional headers to set during the request. - """ - if isinstance(acl_or_str, Policy): - raise InvalidAclError('Attempt to set S3 Policy on GS ACL') - elif isinstance(acl_or_str, ACL): - self.set_def_xml_acl(acl_or_str.to_xml(), headers=headers) - else: - self.set_def_canned_acl(acl_or_str, headers=headers) - - def _get_xml_acl_helper(self, key_name, headers, query_args): - """Provides common functionality for get_xml_acl and _get_acl_helper.""" - response = self.connection.make_request('GET', self.name, key_name, - query_args=query_args, - headers=headers) - body = response.read() - if response.status != 200: - if response.status == 403: - match = ERROR_DETAILS_REGEX.search(body) - details = match.group('details') if match else None - if details: - details = (('<Details>%s. Note that Full Control access' - ' is required to access ACLs.</Details>') % - details) - body = re.sub(ERROR_DETAILS_REGEX, details, body) - raise self.connection.provider.storage_response_error( - response.status, response.reason, body) - return body - - def _get_acl_helper(self, key_name, headers, query_args): - """Provides common functionality for get_acl and get_def_acl.""" - body = self._get_xml_acl_helper(key_name, headers, query_args) - acl = ACL(self) - h = handler.XmlHandler(acl, self) - xml.sax.parseString(body, h) - return acl - - def get_acl(self, key_name='', headers=None, version_id=None, - generation=None): - """Returns the ACL of the bucket or an object in the bucket. - - :param str key_name: The name of the object to get the ACL for. If not - specified, the ACL for the bucket will be returned. - - :param dict headers: Additional headers to set during the request. - - :type version_id: string - :param version_id: Unused in this subclass. - - :param int generation: If specified, gets the ACL for a specific - generation of a versioned object. If not specified, the current - version is returned. This parameter is only valid when retrieving - the ACL of an object, not a bucket. - - :rtype: :class:`.gs.acl.ACL` - """ - query_args = STANDARD_ACL - if generation: - query_args += '&generation=%s' % generation - return self._get_acl_helper(key_name, headers, query_args) - - def get_xml_acl(self, key_name='', headers=None, version_id=None, - generation=None): - """Returns the ACL string of the bucket or an object in the bucket. - - :param str key_name: The name of the object to get the ACL for. If not - specified, the ACL for the bucket will be returned. - - :param dict headers: Additional headers to set during the request. - - :type version_id: string - :param version_id: Unused in this subclass. - - :param int generation: If specified, gets the ACL for a specific - generation of a versioned object. If not specified, the current - version is returned. This parameter is only valid when retrieving - the ACL of an object, not a bucket. - - :rtype: str - """ - query_args = STANDARD_ACL - if generation: - query_args += '&generation=%s' % generation - return self._get_xml_acl_helper(key_name, headers, query_args) - - def get_def_acl(self, headers=None): - """Returns the bucket's default ACL. - - :param dict headers: Additional headers to set during the request. - - :rtype: :class:`.gs.acl.ACL` - """ - return self._get_acl_helper('', headers, DEF_OBJ_ACL) - - def _set_acl_helper(self, acl_or_str, key_name, headers, query_args, - generation, if_generation, if_metageneration, - canned=False): - """Provides common functionality for set_acl, set_xml_acl, - set_canned_acl, set_def_acl, set_def_xml_acl, and - set_def_canned_acl().""" - - headers = headers or {} - data = '' - if canned: - headers[self.connection.provider.acl_header] = acl_or_str - else: - data = acl_or_str - - if generation: - query_args += '&generation=%s' % generation - - if if_metageneration is not None and if_generation is None: - raise ValueError("Received if_metageneration argument with no " - "if_generation argument. A metageneration has no " - "meaning without a content generation.") - if not key_name and (if_generation or if_metageneration): - raise ValueError("Received if_generation or if_metageneration " - "parameter while setting the ACL of a bucket.") - if if_generation is not None: - headers['x-goog-if-generation-match'] = str(if_generation) - if if_metageneration is not None: - headers['x-goog-if-metageneration-match'] = str(if_metageneration) - - response = self.connection.make_request( - 'PUT', get_utf8_value(self.name), get_utf8_value(key_name), - data=get_utf8_value(data), headers=headers, query_args=query_args) - body = response.read() - if response.status != 200: - raise self.connection.provider.storage_response_error( - response.status, response.reason, body) - - def set_xml_acl(self, acl_str, key_name='', headers=None, version_id=None, - query_args='acl', generation=None, if_generation=None, - if_metageneration=None): - """Sets a bucket's or objects's ACL to an XML string. - - :type acl_str: string - :param acl_str: A string containing the ACL XML. - - :type key_name: string - :param key_name: A key name within the bucket to set the ACL for. If not - specified, the ACL for the bucket will be set. - - :type headers: dict - :param headers: Additional headers to set during the request. - - :type version_id: string - :param version_id: Unused in this subclass. - - :type query_args: str - :param query_args: The query parameters to pass with the request. - - :type generation: int - :param generation: If specified, sets the ACL for a specific generation - of a versioned object. If not specified, the current version is - modified. - - :type if_generation: int - :param if_generation: (optional) If set to a generation number, the acl - will only be updated if its current generation number is this value. - - :type if_metageneration: int - :param if_metageneration: (optional) If set to a metageneration number, - the acl will only be updated if its current metageneration number is - this value. - """ - return self._set_acl_helper(acl_str, key_name=key_name, headers=headers, - query_args=query_args, - generation=generation, - if_generation=if_generation, - if_metageneration=if_metageneration) - - def set_canned_acl(self, acl_str, key_name='', headers=None, - version_id=None, generation=None, if_generation=None, - if_metageneration=None): - """Sets a bucket's or objects's ACL using a predefined (canned) value. - - :type acl_str: string - :param acl_str: A canned ACL string. See - :data:`~.gs.acl.CannedACLStrings`. - - :type key_name: string - :param key_name: A key name within the bucket to set the ACL for. If not - specified, the ACL for the bucket will be set. - - :type headers: dict - :param headers: Additional headers to set during the request. - - :type version_id: string - :param version_id: Unused in this subclass. - - :type generation: int - :param generation: If specified, sets the ACL for a specific generation - of a versioned object. If not specified, the current version is - modified. - - :type if_generation: int - :param if_generation: (optional) If set to a generation number, the acl - will only be updated if its current generation number is this value. - - :type if_metageneration: int - :param if_metageneration: (optional) If set to a metageneration number, - the acl will only be updated if its current metageneration number is - this value. - """ - if acl_str not in CannedACLStrings: - raise ValueError("Provided canned ACL string (%s) is not valid." - % acl_str) - query_args = STANDARD_ACL - return self._set_acl_helper(acl_str, key_name, headers, query_args, - generation, if_generation, - if_metageneration, canned=True) - - def set_def_canned_acl(self, acl_str, headers=None): - """Sets a bucket's default ACL using a predefined (canned) value. - - :type acl_str: string - :param acl_str: A canned ACL string. See - :data:`~.gs.acl.CannedACLStrings`. - - :type headers: dict - :param headers: Additional headers to set during the request. - """ - if acl_str not in CannedACLStrings: - raise ValueError("Provided canned ACL string (%s) is not valid." - % acl_str) - query_args = DEF_OBJ_ACL - return self._set_acl_helper(acl_str, '', headers, query_args, - generation=None, if_generation=None, - if_metageneration=None, canned=True) - - def set_def_xml_acl(self, acl_str, headers=None): - """Sets a bucket's default ACL to an XML string. - - :type acl_str: string - :param acl_str: A string containing the ACL XML. - - :type headers: dict - :param headers: Additional headers to set during the request. - """ - return self.set_xml_acl(acl_str, '', headers, - query_args=DEF_OBJ_ACL) - - def get_cors(self, headers=None): - """Returns a bucket's CORS XML document. - - :param dict headers: Additional headers to send with the request. - :rtype: :class:`~.cors.Cors` - """ - response = self.connection.make_request('GET', self.name, - query_args=CORS_ARG, - headers=headers) - body = response.read() - if response.status == 200: - # Success - parse XML and return Cors object. - cors = Cors() - h = handler.XmlHandler(cors, self) - xml.sax.parseString(body, h) - return cors - else: - raise self.connection.provider.storage_response_error( - response.status, response.reason, body) - - def set_cors(self, cors, headers=None): - """Sets a bucket's CORS XML document. - - :param str cors: A string containing the CORS XML. - :param dict headers: Additional headers to send with the request. - """ - response = self.connection.make_request( - 'PUT', get_utf8_value(self.name), data=get_utf8_value(cors), - query_args=CORS_ARG, headers=headers) - body = response.read() - if response.status != 200: - raise self.connection.provider.storage_response_error( - response.status, response.reason, body) - - def get_storage_class(self, headers=None): - """ - Returns the StorageClass for the bucket. - - :rtype: str - :return: The StorageClass for the bucket. - """ - response = self.connection.make_request('GET', self.name, - query_args=STORAGE_CLASS_ARG, - headers=headers) - body = response.read() - if response.status == 200: - rs = ResultSet(self) - h = handler.XmlHandler(rs, self) - xml.sax.parseString(body, h) - return rs.StorageClass - else: - raise self.connection.provider.storage_response_error( - response.status, response.reason, body) - - def set_storage_class(self, storage_class, headers=None): - """ - Sets a bucket's storage class. - - :param str storage_class: A string containing the storage class. - :param dict headers: Additional headers to send with the request. - """ - req_body = self.StorageClassBody % (get_utf8_value(storage_class)) - self.set_subresource(STORAGE_CLASS_ARG, req_body, headers=headers) - - # Method with same signature as boto.s3.bucket.Bucket.add_email_grant(), - # to allow polymorphic treatment at application layer. - def add_email_grant(self, permission, email_address, - recursive=False, headers=None): - """ - Convenience method that provides a quick way to add an email grant - to a bucket. This method retrieves the current ACL, creates a new - grant based on the parameters passed in, adds that grant to the ACL - and then PUT's the new ACL back to GCS. - - :type permission: string - :param permission: The permission being granted. Should be one of: - (READ, WRITE, FULL_CONTROL). - - :type email_address: string - :param email_address: The email address associated with the GS - account your are granting the permission to. - - :type recursive: bool - :param recursive: A boolean value to controls whether the call - will apply the grant to all keys within the bucket - or not. The default value is False. By passing a - True value, the call will iterate through all keys - in the bucket and apply the same grant to each key. - CAUTION: If you have a lot of keys, this could take - a long time! - """ - if permission not in GSPermissions: - raise self.connection.provider.storage_permissions_error( - 'Unknown Permission: %s' % permission) - acl = self.get_acl(headers=headers) - acl.add_email_grant(permission, email_address) - self.set_acl(acl, headers=headers) - if recursive: - for key in self: - key.add_email_grant(permission, email_address, headers=headers) - - # Method with same signature as boto.s3.bucket.Bucket.add_user_grant(), - # to allow polymorphic treatment at application layer. - def add_user_grant(self, permission, user_id, recursive=False, - headers=None): - """ - Convenience method that provides a quick way to add a canonical user - grant to a bucket. This method retrieves the current ACL, creates a new - grant based on the parameters passed in, adds that grant to the ACL and - then PUTs the new ACL back to GCS. - - :type permission: string - :param permission: The permission being granted. Should be one of: - (READ|WRITE|FULL_CONTROL) - - :type user_id: string - :param user_id: The canonical user id associated with the GS account - you are granting the permission to. - - :type recursive: bool - :param recursive: A boolean value to controls whether the call - will apply the grant to all keys within the bucket - or not. The default value is False. By passing a - True value, the call will iterate through all keys - in the bucket and apply the same grant to each key. - CAUTION: If you have a lot of keys, this could take - a long time! - """ - if permission not in GSPermissions: - raise self.connection.provider.storage_permissions_error( - 'Unknown Permission: %s' % permission) - acl = self.get_acl(headers=headers) - acl.add_user_grant(permission, user_id) - self.set_acl(acl, headers=headers) - if recursive: - for key in self: - key.add_user_grant(permission, user_id, headers=headers) - - def add_group_email_grant(self, permission, email_address, recursive=False, - headers=None): - """ - Convenience method that provides a quick way to add an email group - grant to a bucket. This method retrieves the current ACL, creates a new - grant based on the parameters passed in, adds that grant to the ACL and - then PUT's the new ACL back to GCS. - - :type permission: string - :param permission: The permission being granted. Should be one of: - READ|WRITE|FULL_CONTROL - See http://code.google.com/apis/storage/docs/developer-guide.html#authorization - for more details on permissions. - - :type email_address: string - :param email_address: The email address associated with the Google - Group to which you are granting the permission. - - :type recursive: bool - :param recursive: A boolean value to controls whether the call - will apply the grant to all keys within the bucket - or not. The default value is False. By passing a - True value, the call will iterate through all keys - in the bucket and apply the same grant to each key. - CAUTION: If you have a lot of keys, this could take - a long time! - """ - if permission not in GSPermissions: - raise self.connection.provider.storage_permissions_error( - 'Unknown Permission: %s' % permission) - acl = self.get_acl(headers=headers) - acl.add_group_email_grant(permission, email_address) - self.set_acl(acl, headers=headers) - if recursive: - for key in self: - key.add_group_email_grant(permission, email_address, - headers=headers) - - # Method with same input signature as boto.s3.bucket.Bucket.list_grants() - # (but returning different object type), to allow polymorphic treatment - # at application layer. - def list_grants(self, headers=None): - """Returns the ACL entries applied to this bucket. - - :param dict headers: Additional headers to send with the request. - :rtype: list containing :class:`~.gs.acl.Entry` objects. - """ - acl = self.get_acl(headers=headers) - return acl.entries - - def disable_logging(self, headers=None): - """Disable logging on this bucket. - - :param dict headers: Additional headers to send with the request. - """ - xml_str = '<?xml version="1.0" encoding="UTF-8"?><Logging/>' - self.set_subresource('logging', xml_str, headers=headers) - - def enable_logging(self, target_bucket, target_prefix=None, headers=None): - """Enable logging on a bucket. - - :type target_bucket: bucket or string - :param target_bucket: The bucket to log to. - - :type target_prefix: string - :param target_prefix: The prefix which should be prepended to the - generated log files written to the target_bucket. - - :param dict headers: Additional headers to send with the request. - """ - if isinstance(target_bucket, Bucket): - target_bucket = target_bucket.name - xml_str = '<?xml version="1.0" encoding="UTF-8"?><Logging>' - xml_str = (xml_str + '<LogBucket>%s</LogBucket>' % target_bucket) - if target_prefix: - xml_str = (xml_str + - '<LogObjectPrefix>%s</LogObjectPrefix>' % target_prefix) - xml_str = xml_str + '</Logging>' - - self.set_subresource('logging', xml_str, headers=headers) - - def get_logging_config_with_xml(self, headers=None): - """Returns the current status of logging configuration on the bucket as - unparsed XML. - - :param dict headers: Additional headers to send with the request. - - :rtype: 2-Tuple - :returns: 2-tuple containing: - - 1) A dictionary containing the parsed XML response from GCS. The - overall structure is: - - * Logging - - * LogObjectPrefix: Prefix that is prepended to log objects. - * LogBucket: Target bucket for log objects. - - 2) Unparsed XML describing the bucket's logging configuration. - """ - response = self.connection.make_request('GET', self.name, - query_args='logging', - headers=headers) - body = response.read() - boto.log.debug(body) - - if response.status != 200: - raise self.connection.provider.storage_response_error( - response.status, response.reason, body) - - e = boto.jsonresponse.Element() - h = boto.jsonresponse.XmlHandler(e, None) - h.parse(body) - return e, body - - def get_logging_config(self, headers=None): - """Returns the current status of logging configuration on the bucket. - - :param dict headers: Additional headers to send with the request. - - :rtype: dict - :returns: A dictionary containing the parsed XML response from GCS. The - overall structure is: - - * Logging - - * LogObjectPrefix: Prefix that is prepended to log objects. - * LogBucket: Target bucket for log objects. - """ - return self.get_logging_config_with_xml(headers)[0] - - def configure_website(self, main_page_suffix=None, error_key=None, - headers=None): - """Configure this bucket to act as a website - - :type main_page_suffix: str - :param main_page_suffix: Suffix that is appended to a request that is - for a "directory" on the website endpoint (e.g. if the suffix is - index.html and you make a request to samplebucket/images/ the data - that is returned will be for the object with the key name - images/index.html). The suffix must not be empty and must not - include a slash character. This parameter is optional and the - property is disabled if excluded. - - :type error_key: str - :param error_key: The object key name to use when a 400 error occurs. - This parameter is optional and the property is disabled if excluded. - - :param dict headers: Additional headers to send with the request. - """ - if main_page_suffix: - main_page_frag = self.WebsiteMainPageFragment % main_page_suffix - else: - main_page_frag = '' - - if error_key: - error_frag = self.WebsiteErrorFragment % error_key - else: - error_frag = '' - - body = self.WebsiteBody % (main_page_frag, error_frag) - response = self.connection.make_request( - 'PUT', get_utf8_value(self.name), data=get_utf8_value(body), - query_args='websiteConfig', headers=headers) - body = response.read() - if response.status == 200: - return True - else: - raise self.connection.provider.storage_response_error( - response.status, response.reason, body) - - def get_website_configuration(self, headers=None): - """Returns the current status of website configuration on the bucket. - - :param dict headers: Additional headers to send with the request. - - :rtype: dict - :returns: A dictionary containing the parsed XML response from GCS. The - overall structure is: - - * WebsiteConfiguration - - * MainPageSuffix: suffix that is appended to request that - is for a "directory" on the website endpoint. - * NotFoundPage: name of an object to serve when site visitors - encounter a 404. - """ - return self.get_website_configuration_with_xml(headers)[0] - - def get_website_configuration_with_xml(self, headers=None): - """Returns the current status of website configuration on the bucket as - unparsed XML. - - :param dict headers: Additional headers to send with the request. - - :rtype: 2-Tuple - :returns: 2-tuple containing: - - 1) A dictionary containing the parsed XML response from GCS. The - overall structure is: - - * WebsiteConfiguration - - * MainPageSuffix: suffix that is appended to request that is for - a "directory" on the website endpoint. - * NotFoundPage: name of an object to serve when site visitors - encounter a 404 - - 2) Unparsed XML describing the bucket's website configuration. - """ - response = self.connection.make_request('GET', self.name, - query_args='websiteConfig', headers=headers) - body = response.read() - boto.log.debug(body) - - if response.status != 200: - raise self.connection.provider.storage_response_error( - response.status, response.reason, body) - - e = boto.jsonresponse.Element() - h = boto.jsonresponse.XmlHandler(e, None) - h.parse(body) - return e, body - - def delete_website_configuration(self, headers=None): - """Remove the website configuration from this bucket. - - :param dict headers: Additional headers to send with the request. - """ - self.configure_website(headers=headers) - - def get_versioning_status(self, headers=None): - """Returns the current status of versioning configuration on the bucket. - - :rtype: bool - """ - response = self.connection.make_request('GET', self.name, - query_args='versioning', - headers=headers) - body = response.read() - boto.log.debug(body) - if response.status != 200: - raise self.connection.provider.storage_response_error( - response.status, response.reason, body) - resp_json = boto.jsonresponse.Element() - boto.jsonresponse.XmlHandler(resp_json, None).parse(body) - resp_json = resp_json['VersioningConfiguration'] - return ('Status' in resp_json) and (resp_json['Status'] == 'Enabled') - - def configure_versioning(self, enabled, headers=None): - """Configure versioning for this bucket. - - :param bool enabled: If set to True, enables versioning on this bucket. - If set to False, disables versioning. - - :param dict headers: Additional headers to send with the request. - """ - if enabled == True: - req_body = self.VersioningBody % ('Enabled') - else: - req_body = self.VersioningBody % ('Suspended') - self.set_subresource('versioning', req_body, headers=headers) - - def get_lifecycle_config(self, headers=None): - """ - Returns the current lifecycle configuration on the bucket. - - :rtype: :class:`boto.gs.lifecycle.LifecycleConfig` - :returns: A LifecycleConfig object that describes all current - lifecycle rules in effect for the bucket. - """ - response = self.connection.make_request('GET', self.name, - query_args=LIFECYCLE_ARG, headers=headers) - body = response.read() - boto.log.debug(body) - if response.status == 200: - lifecycle_config = LifecycleConfig() - h = handler.XmlHandler(lifecycle_config, self) - xml.sax.parseString(body, h) - return lifecycle_config - else: - raise self.connection.provider.storage_response_error( - response.status, response.reason, body) - - def configure_lifecycle(self, lifecycle_config, headers=None): - """ - Configure lifecycle for this bucket. - - :type lifecycle_config: :class:`boto.gs.lifecycle.LifecycleConfig` - :param lifecycle_config: The lifecycle configuration you want - to configure for this bucket. - """ - xml = lifecycle_config.to_xml() - response = self.connection.make_request( - 'PUT', get_utf8_value(self.name), data=get_utf8_value(xml), - query_args=LIFECYCLE_ARG, headers=headers) - body = response.read() - if response.status == 200: - return True - else: - raise self.connection.provider.storage_response_error( - response.status, response.reason, body) - - def get_billing_config(self, headers=None): - """Returns the current status of billing configuration on the bucket. - - :param dict headers: Additional headers to send with the request. - - :rtype: dict - :returns: A dictionary containing the parsed XML response from GCS. The - overall structure is: - - * BillingConfiguration - - * RequesterPays: Enabled/Disabled. - """ - return self.get_billing_configuration_with_xml(headers)[0] - - def get_billing_configuration_with_xml(self, headers=None): - """Returns the current status of billing configuration on the bucket as - unparsed XML. - - :param dict headers: Additional headers to send with the request. - - :rtype: 2-Tuple - :returns: 2-tuple containing: - - 1) A dictionary containing the parsed XML response from GCS. The - overall structure is: - - * BillingConfiguration - - * RequesterPays: Enabled/Disabled. - - 2) Unparsed XML describing the bucket's website configuration. - """ - response = self.connection.make_request('GET', self.name, - query_args='billing', - headers=headers) - body = response.read() - boto.log.debug(body) - - if response.status != 200: - raise self.connection.provider.storage_response_error( - response.status, response.reason, body) - - e = boto.jsonresponse.Element() - h = boto.jsonresponse.XmlHandler(e, None); - h.parse(body) - return e, body - - def configure_billing(self, requester_pays=False, headers=None): - """Configure billing for this bucket. - - :param bool requester_pays: If set to True, enables requester pays on - this bucket. If set to False, disables requester pays. - - :param dict headers: Additional headers to send with the request. - """ - if requester_pays == True: - req_body = self.BillingBody % ('Enabled') - else: - req_body = self.BillingBody % ('Disabled') - self.set_subresource('billing', req_body, headers=headers) - - def get_encryption_config(self, headers=None): - """Returns a bucket's EncryptionConfig. - - :param dict headers: Additional headers to send with the request. - :rtype: :class:`~.encryption_config.EncryptionConfig` - """ - response = self.connection.make_request( - 'GET', self.name, query_args=ENCRYPTION_CONFIG_ARG, headers=headers) - body = response.read() - if response.status == 200: - # Success - parse XML and return EncryptionConfig object. - encryption_config = EncryptionConfig() - h = handler.XmlHandler(encryption_config, self) - xml.sax.parseString(body, h) - return encryption_config - else: - raise self.connection.provider.storage_response_error( - response.status, response.reason, body) - - def _construct_encryption_config_xml(self, default_kms_key_name=None): - """Creates an XML document for setting a bucket's EncryptionConfig. - - This method is internal as it's only here for testing purposes. As - managing Cloud KMS resources for testing is complex, we settle for - testing that we're creating correctly-formed XML for setting a bucket's - encryption configuration. - - :param str default_kms_key_name: A string containing a fully-qualified - Cloud KMS key name. - :rtype: str - """ - if default_kms_key_name: - default_kms_key_name_frag = ( - self.EncryptionConfigDefaultKeyNameFragment % - default_kms_key_name) - else: - default_kms_key_name_frag = '' - - return self.EncryptionConfigBody % default_kms_key_name_frag - - - def set_encryption_config(self, default_kms_key_name=None, headers=None): - """Sets a bucket's EncryptionConfig XML document. - - :param str default_kms_key_name: A string containing a fully-qualified - Cloud KMS key name. - :param dict headers: Additional headers to send with the request. - """ - body = self._construct_encryption_config_xml( - default_kms_key_name=default_kms_key_name) - response = self.connection.make_request( - 'PUT', get_utf8_value(self.name), data=get_utf8_value(body), - query_args=ENCRYPTION_CONFIG_ARG, headers=headers) - body = response.read() - if response.status != 200: - raise self.connection.provider.storage_response_error( - response.status, response.reason, body)