Skip to content

Commit

Permalink
Updating the Resource Manager Overview.
Browse files Browse the repository at this point in the history
Also making the Connection constructor fail on a service account
credential and disabling the Client factories for service
accounts.
  • Loading branch information
dhermes committed Aug 25, 2015
1 parent 95afe66 commit a3ff6c7
Show file tree
Hide file tree
Showing 5 changed files with 130 additions and 0 deletions.
74 changes: 74 additions & 0 deletions docs/resource-manager-api.rst
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,77 @@ With this API, you can do the following:
- Update existing projects
- Delete projects
- Undelete, or recover, projects that you don't want to delete

.. note::

Don't forget to look at the :ref:`Authentication` section below.
It's slightly different from the rest of this library.

Here's a quick example of the full life-cycle:

.. code-block:: python
>>> from gcloud import resource_manager
>>> # List all projects you have access to
>>> client = resource_manager.Client()
>>> for project in client.list_projects():
... print(project)
>>> # Create a new project
>>> new_project = client.project('your-project-id-here',
... name='My new project)
>>> new_project.create()
>>> # Update an existing project
>>> project = client.get_project('my-existing-project')
>>> print(project)
<Project: Existing Project (my-existing-project)>
>>> project.name = 'Modified name'
>>> project.update()
>>> print(project)
<Project: Modified name (my-existing-project)>
>>> # Delete a project
>>> project = client.get_project('my-existing-project')
>>> project.delete()
>>> # Undelete a project
>>> project = client.get_project('my-existing-project')
>>> project.undelete()
.. _Authentication:
Authentication
~~~~~~~~~~~~~~
Unlike the other APIs, the Resource Manager API is focused on managing your
various projects inside Google Cloud Platform. What this means (currently, as
of August 2015) is that you can't use a Service Account to work with some
parts of this API (for example, creating projects).
The reason is actually pretty simple: if your API call is trying to do
something like create a project, what project's Service Account can you use?
Currently none.
This means that for this API you should always use the credentials
provided by the `Google Cloud SDK`_, which you can get by running
``gcloud auth login``.
.. _Google Cloud SDK: http://cloud.google.com/sdk
Once you run that command, ``gcloud-python`` will automatically pick up the
credentials, and you can use the "automatic discovery" feature of the library.
Start by authenticating:
.. code-block:: bash
$ gcloud auth login
And then simply create a client:
.. code-block:: python
>>> from gcloud import resource_manager
>>> client = resource_manager.Client()
30 changes: 30 additions & 0 deletions gcloud/resource_manager/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,36 @@ class Client(BaseClient):

_connection_class = Connection

@classmethod
def from_service_account_json(cls, *args, **kwargs):
"""Factory to retrieve JSON credentials while creating client.
The behavior from the parent class is disabled here since the Resource
Manager API can only use credentials from a user account, not a
service account.
:raises: :class:`NotImplementedError <exceptions.NotImplementedError>`
always.
"""
raise NotImplementedError('A service account cannot be used with the '
'Resource Manager API. Only user credentials '
'cab be used.')

@classmethod
def from_service_account_p12(cls, *args, **kwargs):
"""Factory to retrieve P12 credentials while creating client.
The behavior from the parent class is disabled here since the Resource
Manager API can only use credentials from a user account, not a
service account.
:raises: :class:`NotImplementedError <exceptions.NotImplementedError>`
always.
"""
raise NotImplementedError('A service account cannot be used with the '
'Resource Manager API. Only user credentials '
'cab be used.')

def project(self, project_id, name=None, labels=None):
"""Creates a :class:`.Project` bound to the current client.
Expand Down
9 changes: 9 additions & 0 deletions gcloud/resource_manager/connection.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@

"""Create / interact with gcloud.resource_manager connections."""


from oauth2client.client import AssertionCredentials

from gcloud import connection as base_connection


Expand All @@ -34,5 +37,11 @@ class Connection(base_connection.JSONConnection):
"""A template for the URL of a particular API call."""

def __init__(self, credentials=None, http=None):
if isinstance(credentials, AssertionCredentials):
message = ('credentials (%r) inherits from '
'AppAssertionCredentials. Only user credentials can be '
'used with the Resource Manager API. '% (credentials,))
raise TypeError(message)

credentials = self._create_scoped_credentials(credentials, SCOPE)
super(Connection, self).__init__(credentials=credentials, http=http)
10 changes: 10 additions & 0 deletions gcloud/resource_manager/test_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,16 @@ def test_constructor(self):
self.assertEqual(client.connection._credentials, credentials)
self.assertEqual(client.connection._http, http)

def test_from_service_account_json_factory(self):
klass = self._getTargetClass()
with self.assertRaises(NotImplementedError):
klass.from_service_account_json()

def test_from_service_account_p12_factory(self):
klass = self._getTargetClass()
with self.assertRaises(NotImplementedError):
klass.from_service_account_p12()

def test_project_factory(self):
from gcloud.resource_manager.project import Project

Expand Down
7 changes: 7 additions & 0 deletions gcloud/resource_manager/test_connection.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,13 @@ def _getTargetClass(self):
def _makeOne(self, *args, **kw):
return self._getTargetClass()(*args, **kw)

def test_constructor_with_assertion(self):
from oauth2client.client import AssertionCredentials

credentials = AssertionCredentials(None)
with self.assertRaises(TypeError):
self._makeOne(credentials=credentials)

def test_build_api_url_no_extra_query_params(self):
conn = self._makeOne()
URI = '/'.join([
Expand Down

0 comments on commit a3ff6c7

Please sign in to comment.