From 02dcded9189796cceaf46ffd53cdf57ee1f00d2c Mon Sep 17 00:00:00 2001 From: Tres Seaver Date: Tue, 4 Nov 2014 15:01:03 -0500 Subject: [PATCH] Add support for the Bucket's 'logging' field. See: https://cloud.google.com/storage/docs/accesslogs Addresses 'logging' part of #314. --- gcloud/storage/bucket.py | 40 +++++++++++++ gcloud/storage/test_bucket.py | 102 ++++++++++++++++++++++++++++++++++ 2 files changed, 142 insertions(+) diff --git a/gcloud/storage/bucket.py b/gcloud/storage/bucket.py index 6efa3a0d7afb..b9d5f283a012 100644 --- a/gcloud/storage/bucket.py +++ b/gcloud/storage/bucket.py @@ -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.""" @@ -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. diff --git a/gcloud/storage/test_bucket.py b/gcloud/storage/test_bucket.py index 7ca687acea76..d98964abf0e9 100644 --- a/gcloud/storage/test_bucket.py +++ b/gcloud/storage/test_bucket.py @@ -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'} @@ -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):