Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove "Storage Admin" role requirement. #412

Closed
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 1 addition & 2 deletions AUTHORS
Expand Up @@ -34,10 +34,9 @@ By order of apparition, thanks:
* Max Malysh (Dropbox large file support)
* Scott White (Google Cloud updates)
* Alex Watt (Google Cloud Storage patch)
* Janusz Skonieczny (Google Cloud Storage limited permission workaround)
* Jumpei Yoshimura (S3 docs)
* Jon Dufresne



Extra thanks to Marty for adding this in Django,
you can buy his very interesting book (Pro Django).
9 changes: 9 additions & 0 deletions storages/backends/gcloud.py
Expand Up @@ -7,6 +7,7 @@
from django.utils import timezone
from django.utils.deconstruct import deconstructible
from django.utils.encoding import force_bytes, smart_str
from google.cloud.storage import Bucket

from storages.utils import check_location, clean_name, safe_join, setting

Expand Down Expand Up @@ -84,6 +85,7 @@ class GoogleCloudStorage(Storage):
bucket_name = setting('GS_BUCKET_NAME')
location = setting('GS_LOCATION', '')
auto_create_bucket = setting('GS_AUTO_CREATE_BUCKET', False)
always_get_bucket = setting('GS_ALWAYS_GET_BUCKET', True)
auto_create_acl = setting('GS_AUTO_CREATE_ACL', 'projectPrivate')
default_acl = setting('GS_DEFAULT_ACL')

Expand Down Expand Up @@ -125,6 +127,13 @@ def _get_or_create_bucket(self, name):
"""
Retrieves a bucket if it exists, otherwise creates it.
"""
if not self.always_get_bucket:
# If permissions are limited. Call to get_bucket (below) results in:
# 403 Caller does not have storage.buckets.get access to bucket.
# Even if bucket actually exists
# So we don't get_bucket, we just create it's proxy here
return Bucket(client=self.client, name=name)

try:
return self.client.get_bucket(name)
except NotFound:
Expand Down
32 changes: 31 additions & 1 deletion tests/test_gcloud.py
@@ -1,5 +1,4 @@
# -*- coding: utf-8 -*-

try:
from unittest import mock
except ImportError: # Python 3.2 and below
Expand All @@ -19,6 +18,7 @@


class GCloudTestCase(TestCase):

def setUp(self):
self.bucket_name = 'test_bucket'
self.filename = 'test_file.txt'
Expand Down Expand Up @@ -169,6 +169,36 @@ def test_exists_bucket_auto_create(self):
self.assertTrue(self.storage.exists(''))
self.storage._client.create_bucket.assert_called_with(self.bucket_name)

def test_bucket_auto_create_true(self):
self.storage.auto_create_bucket = True
self.storage._client = mock.MagicMock()
self.storage._client.get_bucket.side_effect = NotFound('dang')

self.assertIsNotNone(self.storage.bucket)
self.storage._client.create_bucket.assert_called_with(self.bucket_name)

def test_bucket_always_get_bucket_false(self):
"""
If auto_create_bucket is False getting a bucket property should not bother
with checking for bucket existence.

If permissions are limited. Call to get_bucket (below) results in:
403 Caller does not have storage.buckets.get access to bucket.
Even if bucket actually exists

Let it fail later on usage of non-existent buckets.

This prevents preemptive fails when client user does not have privileges to create buckets.
"""
self.storage.always_get_bucket = False
self.storage._client = mock.MagicMock()

bucket = self.storage.bucket
self.assertFalse(self.storage._client.get_bucket.called)
self.assertIsNotNone(bucket)
self.assertEqual(bucket.name, self.bucket_name)
self.assertEqual(bucket.client, self.storage._client)

def test_listdir(self):
file_names = ["some/path/1.txt", "2.txt", "other/path/3.txt", "4.txt"]
subdir = ""
Expand Down
4 changes: 4 additions & 0 deletions tox.ini
Expand Up @@ -26,6 +26,7 @@ deps =
boto3
dropbox
google-cloud-storage
cryptography<2.0 ; python_version < '3.4'
paramiko

[testenv:flake8]
Expand All @@ -35,3 +36,6 @@ deps =
commands =
flake8
isort --recursive --check-only --diff storages/ tests/

[pytest]
DJANGO_SETTINGS_MODULE = tests.settings