Use keystone v3 and get a project scoped token

Change to use the keystone v3 client. Rename os-tenant-id to
os-project id and os-tenant-name to os-project-name to match
keystone v3

Validate token is a project scoped token if the token is
fetched using user and password and not passed in

Allow the user to specify os-domain-name or os-domain-id if
needed to resolve os-project-name

Change-Id: I19fe2d9af5f0f862303066bb235826373e6d605f
This commit is contained in:
Craig Bryant 2014-11-02 22:19:22 -07:00
parent aa1c054dc5
commit 6a83c8d8a2
3 changed files with 72 additions and 35 deletions

View File

@ -23,7 +23,7 @@ import argparse
import logging
import sys
from keystoneclient.v2_0 import client as ksclient
from keystoneclient.v3 import client as ksclient
import monascaclient
from monascaclient import client as monasca_client
@ -115,18 +115,32 @@ class MonascaShell(object):
parser.add_argument('--os_password',
help=argparse.SUPPRESS)
parser.add_argument('--os-tenant-id',
default=utils.env('OS_TENANT_ID'),
help='Defaults to env[OS_TENANT_ID].')
parser.add_argument('--os-project-id',
default=utils.env('OS_PROJECT_ID'),
help='Defaults to env[OS_PROJECT_ID].')
parser.add_argument('--os_tenant_id',
parser.add_argument('--os_project_id',
help=argparse.SUPPRESS)
parser.add_argument('--os-tenant-name',
default=utils.env('OS_TENANT_NAME'),
help='Defaults to env[OS_TENANT_NAME].')
parser.add_argument('--os-project-name',
default=utils.env('OS_PROJECT_NAME'),
help='Defaults to env[OS_PROJECT_NAME].')
parser.add_argument('--os_tenant_name',
parser.add_argument('--os_project_name',
help=argparse.SUPPRESS)
parser.add_argument('--os-domain-id',
default=utils.env('OS_DOMAIN_ID'),
help='Defaults to env[OS_DOMAIN_ID].')
parser.add_argument('--os_domain_id',
help=argparse.SUPPRESS)
parser.add_argument('--os-domain-name',
default=utils.env('OS_DOMAIN_NAME'),
help='Defaults to env[OS_DOMAIN_NAME].')
parser.add_argument('--os_domain_name',
help=argparse.SUPPRESS)
parser.add_argument('--os-auth-url',
@ -236,18 +250,24 @@ class MonascaShell(object):
:param username: name of user
:param password: user's password
:param tenant_id: unique identifier of tenant
:param tenant_name: name of tenant
:param project_id: unique identifier of project
:param project_name: name of project
:param domain_name: name of domain project is in
:param domain_id: id of domain project is in
:param auth_url: endpoint to authenticate against
:param token: token to use instead of username/password
"""
kc_args = {'auth_url': kwargs.get('auth_url'),
'insecure': kwargs.get('insecure')}
if kwargs.get('tenant_id'):
kc_args['tenant_id'] = kwargs.get('tenant_id')
else:
kc_args['tenant_name'] = kwargs.get('tenant_name')
if kwargs.get('project_id'):
kc_args['project_id'] = kwargs.get('project_id')
elif kwargs.get('project_name'):
kc_args['project_name'] = kwargs.get('project_name')
if kwargs.get('domain_name'):
kc_args['project_domain_name'] = kwargs.get('domain_name')
if kwargs.get('domain_id'):
kc_args['project_domain_id'] = kwargs.get('domain_id')
if kwargs.get('token'):
kc_args['token'] = kwargs.get('token')
@ -257,6 +277,24 @@ class MonascaShell(object):
return ksclient.Client(**kc_args)
def _get_token(self, _ksclient):
"""Validate token is project scoped and return it if it is
project_id and auth_token were fetched when keystone client was created
:param _ksclient: keystone client
"""
if _ksclient.project_id:
return _ksclient.auth_token
raise exc.CommandError("User does not have a default project. "
"You must provide a project id using "
"--os-project-id or via env[OS_PROJECT_ID], "
"or you must provide a project name using "
"--os-project-name or via env[OS_PROJECT_NAME] "
"and a domain using --os-domain-name, via "
"env[OS_DOMAIN_NAME], using --os-domain-id or "
"via env[OS_DOMAIN_ID]")
def _get_endpoint(self, client, **kwargs):
"""Get an endpoint using the provided keystone client."""
if kwargs.get('region_name'):
@ -327,14 +365,6 @@ class MonascaShell(object):
" via either --monasca-api-url or"
" env[MONASCA_API_URL]")
else:
# Tenant name or ID is needed to make keystoneclient retrieve a
# service catalog, it's not required if os_no_client_auth is
# specified, neither is the auth URL
if not (args.os_tenant_id or args.os_tenant_name):
raise exc.CommandError("You must provide a tenant_id via"
" either --os-tenant-id or via"
" env[OS_TENANT_ID]")
if not args.os_auth_url:
raise exc.CommandError("You must provide an auth url via"
" either --os-auth-url or via"
@ -344,11 +374,13 @@ class MonascaShell(object):
'username': args.os_username,
'password': args.os_password,
'token': args.os_auth_token,
'tenant_id': args.os_tenant_id,
'tenant_name': args.os_tenant_name,
'auth_url': args.os_auth_url,
'service_type': args.os_service_type,
'endpoint_type': args.os_endpoint_type,
'project_id': args.os_project_id,
'project_name': args.os_project_name,
'domain_id': args.os_domain_id,
'domain_name': args.os_domain_name,
'insecure': args.insecure
}
@ -356,7 +388,10 @@ class MonascaShell(object):
if not args.os_no_client_auth:
_ksclient = self._get_ksclient(**kwargs)
token = args.os_auth_token or _ksclient.auth_token
if args.os_auth_token:
token = args.os_auth_token
else:
token = self._get_token(_ksclient)
kwargs = {
'token': token,

View File

@ -13,7 +13,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
from keystoneclient.v2_0 import client as ksclient
from keystoneclient.v3 import client as ksclient
from monascaclient.openstack.common import jsonutils
@ -23,14 +23,14 @@ def script_keystone_client(token=None):
ksclient.Client(auth_url='http://no.where',
insecure=False,
tenant_id='tenant_id',
token=token).AndReturn(FakeKeystone(token))
token=token).AndReturn(FakeKeystone(token, None))
else:
ksclient.Client(auth_url='http://no.where',
insecure=False,
password='password',
tenant_name='tenant_name',
project_name='project_name',
username='username').AndReturn(FakeKeystone(
'abcd1234'))
'abcd1234', 'test'))
def fake_headers():
@ -49,8 +49,9 @@ class FakeServiceCatalog():
class FakeKeystone():
service_catalog = FakeServiceCatalog()
def __init__(self, auth_token):
def __init__(self, auth_token, project_id):
self.auth_token = auth_token
self.project_id = project_id
class FakeRaw():

View File

@ -17,7 +17,7 @@ import re
import sys
import fixtures
from keystoneclient.v2_0 import client as ksclient
from keystoneclient.v3 import client as ksclient
from mox3 import mox
import six
import testtools
@ -31,9 +31,10 @@ from monascaclient.tests import fakes
class TestCase(testtools.TestCase):
def set_fake_env(self, fake_env):
client_env = ('OS_USERNAME', 'OS_PASSWORD', 'OS_TENANT_ID',
'OS_TENANT_NAME', 'OS_AUTH_URL', 'OS_REGION_NAME',
client_env = ('OS_USERNAME', 'OS_PASSWORD', 'OS_PROJECT_ID',
'OS_PROJECT_NAME', 'OS_AUTH_URL', 'OS_REGION_NAME',
'OS_AUTH_TOKEN', 'OS_NO_CLIENT_AUTH', 'OS_SERVICE_TYPE',
'OS_DOMAIN_NAME', 'OS_DOMAIN_ID',
'OS_ENDPOINT_TYPE', 'MONASCA_API_URL')
for key in client_env:
@ -152,7 +153,7 @@ class ShellTestMonascaCommands(ShellBase):
fake_env = {
'OS_USERNAME': 'username',
'OS_PASSWORD': 'password',
'OS_TENANT_NAME': 'tenant_name',
'OS_PROJECT_NAME': 'project_name',
'OS_AUTH_URL': 'http://no.where',
}
self.set_fake_env(fake_env)