/boto/gs/bucket.py
Python | 988 lines | 892 code | 21 blank | 75 comment | 17 complexity | d9467dc448036c8a9af3cb37d8b9ee8d MD5 | raw file
- # 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.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
- # constants for http query args
- DEF_OBJ_ACL = 'defaultObjectAcl'
- STANDARD_ACL = 'acl'
- CORS_ARG = 'cors'
- LIFECYCLE_ARG = 'lifecycle'
- ERROR_DETAILS_REGEX = re.compile(r'<Details>(?P<details>.*)</Details>')
- class Bucket(S3Bucket):
- """Represents a Google Cloud Storage bucket."""
- 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 response_headers.iteritems():
- 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, 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):
- """
- Returns the StorageClass for the bucket.
- :rtype: str
- :return: The StorageClass for the bucket.
- """
- response = self.connection.make_request('GET', self.name,
- query_args='storageClass')
- 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)
- # 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)