Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 40 additions & 0 deletions gcloud/storage/bucket.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ class Bucket(_MetadataMixin):
CUSTOM_METADATA_FIELDS = {
'acl': 'get_acl',
'defaultObjectAcl': 'get_default_object_acl',
'logging': 'get_logging',
}
"""Mapping of field name -> accessor for fields w/ custom accessors."""

Expand Down Expand Up @@ -441,6 +442,45 @@ def make_public(self, recursive=False, future=False):
key.get_acl().all().grant_read()
key.save_acl()

def get_logging(self):
"""Return info about access logging for this bucket.

See: https://cloud.google.com/storage/docs/accesslogs#status

:rtype: dict or None
:returns: a dict w/ keys, ``bucket_name`` and ``object_prefix``
(if logging is enabled), or None (if not).
"""
if not self.has_metadata('logging'):
self.reload_metadata()
info = self.metadata.get('logging')
if info is not None:
info = info.copy()
info['bucket_name'] = info.pop('logBucket')
info['object_prefix'] = info.pop('logObjectPrefix', '')
return info

def enable_logging(self, bucket_name, object_prefix=''):
"""Enable access logging for this bucket.

See: https://cloud.google.com/storage/docs/accesslogs#delivery

:type bucket_name: string
:param bucket_name: name of bucket in which to store access logs

:type object_prefix: string
:param object_prefix: prefix for access log filenames
"""
info = {'logBucket': bucket_name, 'logObjectPrefix': object_prefix}
self.patch_metadata({'logging': info})

def disable_logging(self):
"""Disable access logging for this bucket.

See: https://cloud.google.com/storage/docs/accesslogs#disabling
"""
self.patch_metadata({'logging': None})


class BucketIterator(Iterator):
"""An iterator listing all buckets.
Expand Down
102 changes: 102 additions & 0 deletions gcloud/storage/test_bucket.py
Original file line number Diff line number Diff line change
Expand Up @@ -489,6 +489,23 @@ def test_get_metadata_none_set_defaultObjectAcl_miss_clear_default(self):
kw = connection._requested
self.assertEqual(len(kw), 0)

def test_get_metadata_logging_no_default(self):
NAME = 'name'
connection = _Connection()
bucket = self._makeOne(connection, NAME)
self.assertRaises(KeyError, bucket.get_metadata, 'logging')
kw = connection._requested
self.assertEqual(len(kw), 0)

def test_get_metadata_logging_w_default(self):
NAME = 'name'
connection = _Connection()
bucket = self._makeOne(connection, NAME)
default = object()
self.assertRaises(KeyError, bucket.get_metadata, 'logging', default)
kw = connection._requested
self.assertEqual(len(kw), 0)

def test_get_metadata_miss(self):
NAME = 'name'
before = {'bar': 'Bar'}
Expand Down Expand Up @@ -713,6 +730,91 @@ def get_items_from_response(self, response):
self.assertEqual(kw[1]['path'], '/b/%s/o' % NAME)
self.assertEqual(kw[1]['query_params'], None)

def test_get_logging_eager_w_prefix(self):
NAME = 'name'
LOG_BUCKET = 'logs'
LOG_PREFIX = 'pfx'
before = {
'logging': {'logBucket': LOG_BUCKET,
'logObjectPrefix': LOG_PREFIX}}
connection = _Connection()
bucket = self._makeOne(connection, NAME, before)
info = bucket.get_logging()
self.assertEqual(info['bucket_name'], LOG_BUCKET)
self.assertEqual(info['object_prefix'], LOG_PREFIX)
kw = connection._requested
self.assertEqual(len(kw), 0)

def test_get_logging_lazy_wo_prefix(self):
NAME = 'name'
LOG_BUCKET = 'logs'
after = {'logging': {'logBucket': LOG_BUCKET}}
connection = _Connection(after)
bucket = self._makeOne(connection, NAME)
info = bucket.get_logging()
self.assertEqual(info['bucket_name'], LOG_BUCKET)
self.assertEqual(info['object_prefix'], '')
kw = connection._requested
self.assertEqual(len(kw), 1)
self.assertEqual(kw[0]['path'], '/b/%s' % NAME)
self.assertEqual(kw[0]['query_params'], {'projection': 'noAcl'})

def test_enable_logging_defaults(self):
NAME = 'name'
LOG_BUCKET = 'logs'
before = {'logging': None}
after = {'logging': {'logBucket': LOG_BUCKET, 'logObjectPrefix': ''}}
connection = _Connection(after)
bucket = self._makeOne(connection, NAME, before)
self.assertTrue(bucket.get_logging() is None)
bucket.enable_logging(LOG_BUCKET)
info = bucket.get_logging()
self.assertEqual(info['bucket_name'], LOG_BUCKET)
self.assertEqual(info['object_prefix'], '')
kw = connection._requested
self.assertEqual(len(kw), 1)
self.assertEqual(kw[0]['method'], 'PATCH')
self.assertEqual(kw[0]['path'], '/b/%s' % NAME)
self.assertEqual(kw[0]['data'], after)
self.assertEqual(kw[0]['query_params'], {'projection': 'full'})

def test_enable_logging_explicit(self):
NAME = 'name'
LOG_BUCKET = 'logs'
LOG_PFX = 'pfx'
before = {'logging': None}
after = {
'logging': {'logBucket': LOG_BUCKET, 'logObjectPrefix': LOG_PFX}}
connection = _Connection(after)
bucket = self._makeOne(connection, NAME, before)
self.assertTrue(bucket.get_logging() is None)
bucket.enable_logging(LOG_BUCKET, LOG_PFX)
info = bucket.get_logging()
self.assertEqual(info['bucket_name'], LOG_BUCKET)
self.assertEqual(info['object_prefix'], LOG_PFX)
kw = connection._requested
self.assertEqual(len(kw), 1)
self.assertEqual(kw[0]['method'], 'PATCH')
self.assertEqual(kw[0]['path'], '/b/%s' % NAME)
self.assertEqual(kw[0]['data'], after)
self.assertEqual(kw[0]['query_params'], {'projection': 'full'})

def test_disable_logging(self):
NAME = 'name'
before = {'logging': {'logBucket': 'logs', 'logObjectPrefix': 'pfx'}}
after = {'logging': None}
connection = _Connection(after)
bucket = self._makeOne(connection, NAME, before)
self.assertTrue(bucket.get_logging() is not None)
bucket.disable_logging()
self.assertTrue(bucket.get_logging() is None)
kw = connection._requested
self.assertEqual(len(kw), 1)
self.assertEqual(kw[0]['method'], 'PATCH')
self.assertEqual(kw[0]['path'], '/b/%s' % NAME)
self.assertEqual(kw[0]['data'], {'logging': None})
self.assertEqual(kw[0]['query_params'], {'projection': 'full'})


class TestBucketIterator(unittest2.TestCase):

Expand Down