Skip to content

Commit 2f44daf

Browse files
authored
Storage: Add 'Client.get_service_account_email'. (googleapis#5765)
Returns email address of service account of a given project, defaulting to the client's project. Closes googleapis#5635.
1 parent eb258ec commit 2f44daf

File tree

3 files changed

+92
-0
lines changed

3 files changed

+92
-0
lines changed

storage/google/cloud/storage/client.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,24 @@ def current_batch(self):
151151
"""
152152
return self._batch_stack.top
153153

154+
def get_service_account_email(self, project=None):
155+
"""Get the email address of the project's GCS service account
156+
157+
:type project: str
158+
:param project:
159+
(Optional) Project ID to use for retreiving GCS service account
160+
email address. Defaults to the client's project.
161+
162+
:rtype: str
163+
:returns: service account email address
164+
"""
165+
if project is None:
166+
project = self.project
167+
path = '/projects/%s/serviceAccount' % (project,)
168+
api_response = self._base_connection.api_request(
169+
method='GET', path=path)
170+
return api_response['email_address']
171+
154172
def bucket(self, bucket_name, user_project=None):
155173
"""Factory constructor for bucket object.
156174

storage/tests/system.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414

1515
import os
1616
import tempfile
17+
import re
1718
import time
1819
import unittest
1920

@@ -82,6 +83,25 @@ def tearDownModule():
8283
retry(Config.TEST_BUCKET.delete)(force=True)
8384

8485

86+
class TestClient(unittest.TestCase):
87+
88+
def test_get_service_account_email(self):
89+
domain = 'gs-project-accounts.iam.gserviceaccount.com'
90+
91+
email = Config.CLIENT.get_service_account_email()
92+
93+
new_style = re.compile(
94+
r'service-(?P<projnum>[^@]+)@' + domain)
95+
old_style = re.compile(
96+
r'{}@{}'.format(Config.CLIENT.project, domain))
97+
patterns = [new_style, old_style]
98+
matches = [pattern.match(email) for pattern in patterns]
99+
100+
self.assertTrue(any(
101+
match for match in matches if match is not None
102+
))
103+
104+
85105
class TestStorageBuckets(unittest.TestCase):
86106

87107
def setUp(self):

storage/tests/unit/test_client.py

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,60 @@ def test__connection_getter_with_batch(self):
173173
self.assertIs(client._connection, batch)
174174
self.assertIs(client.current_batch, batch)
175175

176+
def test_get_service_account_email_wo_project(self):
177+
PROJECT = 'PROJECT'
178+
CREDENTIALS = _make_credentials()
179+
EMAIL = 'storage-user-123@example.com'
180+
RESOURCE = {
181+
'kind': 'storage#serviceAccount',
182+
'email_address': EMAIL,
183+
}
184+
185+
client = self._make_one(project=PROJECT, credentials=CREDENTIALS)
186+
http = _make_requests_session([
187+
_make_json_response(RESOURCE)])
188+
client._http_internal = http
189+
190+
service_account_email = client.get_service_account_email()
191+
192+
self.assertEqual(service_account_email, EMAIL)
193+
URI = '/'.join([
194+
client._connection.API_BASE_URL,
195+
'storage',
196+
client._connection.API_VERSION,
197+
'projects/%s/serviceAccount' % (PROJECT,)
198+
])
199+
http.request.assert_called_once_with(
200+
method='GET', url=URI, data=None, headers=mock.ANY)
201+
202+
def test_get_service_account_email_w_project(self):
203+
PROJECT = 'PROJECT'
204+
OTHER_PROJECT = 'OTHER_PROJECT'
205+
CREDENTIALS = _make_credentials()
206+
EMAIL = 'storage-user-123@example.com'
207+
RESOURCE = {
208+
'kind': 'storage#serviceAccount',
209+
'email_address': EMAIL,
210+
}
211+
212+
client = self._make_one(project=PROJECT, credentials=CREDENTIALS)
213+
http = _make_requests_session([
214+
_make_json_response(RESOURCE)])
215+
client._http_internal = http
216+
217+
service_account_email = client.get_service_account_email(
218+
project=OTHER_PROJECT)
219+
220+
self.assertEqual(service_account_email, EMAIL)
221+
URI = '/'.join([
222+
client._connection.API_BASE_URL,
223+
'storage',
224+
client._connection.API_VERSION,
225+
'projects/%s/serviceAccount' % (OTHER_PROJECT,)
226+
])
227+
http.request.assert_called_once_with(
228+
method='GET', url=URI, data=None, headers=mock.ANY)
229+
176230
def test_bucket(self):
177231
from google.cloud.storage.bucket import Bucket
178232

0 commit comments

Comments
 (0)