Support using the Keystone V3 API from the Nova CLI
This changeset enables support for Keystone V3 authentication on the Nova CLI. This provides consistency between using novaclient as the Nova CLI and using it as a library as the Keystone V3 support already exists for the libary usecase. The bulk of the change surrounds the use of the keystoneclient session object for authentication, retriving the service catalog, and HTTP connection/session management. Co-Authored-By: Morgan Fainberg <morgan.fainberg@gmail.com> Change-Id: Iece9f41320a8770176c7eeb5acd86be4d80cc58f
This commit is contained in:
parent
d485d755ec
commit
8597a0c234
novaclient
@ -137,20 +137,35 @@ class CompletionCache(object):
|
||||
|
||||
class SessionClient(adapter.LegacyJsonAdapter):
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.times = []
|
||||
super(SessionClient, self).__init__(*args, **kwargs)
|
||||
|
||||
def request(self, url, method, **kwargs):
|
||||
# NOTE(jamielennox): The standard call raises errors from
|
||||
# keystoneclient, where we need to raise the novaclient errors.
|
||||
raise_exc = kwargs.pop('raise_exc', True)
|
||||
start_time = time.time()
|
||||
resp, body = super(SessionClient, self).request(url,
|
||||
method,
|
||||
raise_exc=False,
|
||||
**kwargs)
|
||||
|
||||
end_time = time.time()
|
||||
self.times.append(('%s %s' % (method, url),
|
||||
start_time, end_time))
|
||||
|
||||
if raise_exc and resp.status_code >= 400:
|
||||
raise exceptions.from_response(resp, body, url, method)
|
||||
|
||||
return resp, body
|
||||
|
||||
def get_timings(self):
|
||||
return self.times
|
||||
|
||||
def reset_timings(self):
|
||||
self.times = []
|
||||
|
||||
|
||||
def _original_only(f):
|
||||
"""Indicates and enforces that this function can only be used if we are
|
||||
|
@ -28,7 +28,11 @@ import logging
|
||||
import os
|
||||
import pkgutil
|
||||
import sys
|
||||
import time
|
||||
|
||||
from keystoneclient.auth.identity.generic import password
|
||||
from keystoneclient.auth.identity.generic import token
|
||||
from keystoneclient.auth.identity import v3 as identity
|
||||
from keystoneclient import session as ksession
|
||||
from oslo.utils import encodeutils
|
||||
from oslo.utils import strutils
|
||||
@ -232,6 +236,7 @@ class NovaClientArgumentParser(argparse.ArgumentParser):
|
||||
|
||||
|
||||
class OpenStackComputeShell(object):
|
||||
times = []
|
||||
|
||||
def _append_global_identity_args(self, parser):
|
||||
# Register the CLI arguments that have moved to the session object.
|
||||
@ -240,6 +245,14 @@ class OpenStackComputeShell(object):
|
||||
parser.set_defaults(insecure=utils.env('NOVACLIENT_INSECURE',
|
||||
default=False))
|
||||
|
||||
identity.Password.register_argparse_arguments(parser)
|
||||
|
||||
parser.set_defaults(os_username=utils.env('OS_USERNAME',
|
||||
'NOVA_USERNAME'))
|
||||
parser.set_defaults(os_password=utils.env('OS_PASSWORD',
|
||||
'NOVA_PASSWORD'))
|
||||
parser.set_defaults(os_auth_url=utils.env('OS_AUTH_URL', 'NOVA_URL'))
|
||||
|
||||
def get_base_parser(self):
|
||||
parser = NovaClientArgumentParser(
|
||||
prog='nova',
|
||||
@ -281,22 +294,9 @@ class OpenStackComputeShell(object):
|
||||
default=utils.env('OS_AUTH_TOKEN'),
|
||||
help='Defaults to env[OS_AUTH_TOKEN]')
|
||||
|
||||
parser.add_argument('--os-username',
|
||||
metavar='<auth-user-name>',
|
||||
default=utils.env('OS_USERNAME', 'NOVA_USERNAME'),
|
||||
help=_('Defaults to env[OS_USERNAME].'))
|
||||
parser.add_argument('--os_username',
|
||||
help=argparse.SUPPRESS)
|
||||
|
||||
parser.add_argument('--os-user-id',
|
||||
metavar='<auth-user-id>',
|
||||
default=utils.env('OS_USER_ID'),
|
||||
help=_('Defaults to env[OS_USER_ID].'))
|
||||
|
||||
parser.add_argument('--os-password',
|
||||
metavar='<auth-password>',
|
||||
default=utils.env('OS_PASSWORD', 'NOVA_PASSWORD'),
|
||||
help=_('Defaults to env[OS_PASSWORD].'))
|
||||
parser.add_argument('--os_password',
|
||||
help=argparse.SUPPRESS)
|
||||
|
||||
@ -312,10 +312,6 @@ class OpenStackComputeShell(object):
|
||||
default=utils.env('OS_TENANT_ID'),
|
||||
help=_('Defaults to env[OS_TENANT_ID].'))
|
||||
|
||||
parser.add_argument('--os-auth-url',
|
||||
metavar='<auth-url>',
|
||||
default=utils.env('OS_AUTH_URL', 'NOVA_URL'),
|
||||
help=_('Defaults to env[OS_AUTH_URL].'))
|
||||
parser.add_argument('--os_auth_url',
|
||||
help=argparse.SUPPRESS)
|
||||
|
||||
@ -511,6 +507,19 @@ class OpenStackComputeShell(object):
|
||||
logging.basicConfig(level=logging.DEBUG,
|
||||
format=streamformat)
|
||||
|
||||
def _get_keystone_auth(self, session, auth_url, **kwargs):
|
||||
auth_token = kwargs.pop('auth_token', None)
|
||||
if auth_token:
|
||||
return token.Token(auth_url, auth_token, **kwargs)
|
||||
else:
|
||||
return password.Password(auth_url,
|
||||
username=kwargs.pop('username'),
|
||||
user_id=kwargs.pop('user_id'),
|
||||
password=kwargs.pop('password'),
|
||||
user_domain_id=kwargs.pop('user_domain_id'),
|
||||
user_domain_name=kwargs.pop('user_domain_name'),
|
||||
**kwargs)
|
||||
|
||||
def main(self, argv):
|
||||
# Parse args once to find version and debug settings
|
||||
parser = self.get_base_parser()
|
||||
@ -570,6 +579,9 @@ class OpenStackComputeShell(object):
|
||||
cacert = args.os_cacert
|
||||
timeout = args.timeout
|
||||
|
||||
keystone_session = None
|
||||
keystone_auth = None
|
||||
|
||||
# We may have either, both or none of these.
|
||||
# If we have both, we don't need USERNAME, PASSWORD etc.
|
||||
# Fill in the blanks from the SecretsHelper if possible.
|
||||
@ -603,6 +615,13 @@ class OpenStackComputeShell(object):
|
||||
must_auth = not (cliutils.isunauthenticated(args.func)
|
||||
or (auth_token and management_url))
|
||||
|
||||
# Do not use Keystone session for cases with no session support. The
|
||||
# presence of auth_plugin means os_auth_system is present and is not
|
||||
# keystone.
|
||||
use_session = True
|
||||
if auth_plugin or bypass_url or os_cache or volume_service_name:
|
||||
use_session = False
|
||||
|
||||
# FIXME(usrleon): Here should be restrict for project id same as
|
||||
# for os_username or os_password but for compatibility it is not.
|
||||
if must_auth:
|
||||
@ -615,11 +634,14 @@ class OpenStackComputeShell(object):
|
||||
"or user id via --os-username, --os-user-id, "
|
||||
"env[OS_USERNAME] or env[OS_USER_ID]"))
|
||||
|
||||
if not os_tenant_name and not os_tenant_id:
|
||||
raise exc.CommandError(_("You must provide a tenant name "
|
||||
"or tenant id via --os-tenant-name, "
|
||||
"--os-tenant-id, env[OS_TENANT_NAME] "
|
||||
"or env[OS_TENANT_ID]"))
|
||||
if not any([args.os_tenant_name, args.os_tenant_id,
|
||||
args.os_project_id, args.os_project_name]):
|
||||
raise exc.CommandError(_("You must provide a project name or"
|
||||
" project id via --os-project-name,"
|
||||
" --os-project-id, env[OS_PROJECT_ID]"
|
||||
" or env[OS_PROJECT_NAME]. You may"
|
||||
" use os-project and os-tenant"
|
||||
" interchangeably."))
|
||||
|
||||
if not os_auth_url:
|
||||
if os_auth_system and os_auth_system != 'keystone':
|
||||
@ -632,13 +654,39 @@ class OpenStackComputeShell(object):
|
||||
"default url with --os-auth-system "
|
||||
"or env[OS_AUTH_SYSTEM]"))
|
||||
|
||||
project_id = args.os_project_id or args.os_tenant_id
|
||||
project_name = args.os_project_name or args.os_tenant_name
|
||||
if use_session:
|
||||
# Not using Nova auth plugin, so use keystone
|
||||
start_time = time.time()
|
||||
keystone_session = ksession.Session.load_from_cli_options(args)
|
||||
keystone_auth = self._get_keystone_auth(
|
||||
keystone_session,
|
||||
args.os_auth_url,
|
||||
username=args.os_username,
|
||||
user_id=args.os_user_id,
|
||||
user_domain_id=args.os_user_domain_id,
|
||||
user_domain_name=args.os_user_domain_name,
|
||||
password=args.os_password,
|
||||
auth_token=args.os_auth_token,
|
||||
project_id=project_id,
|
||||
project_name=project_name,
|
||||
project_domain_id=args.os_project_domain_id,
|
||||
project_domain_name=args.os_project_domain_name)
|
||||
end_time = time.time()
|
||||
self.times.append(('%s %s' % ('auth_url', args.os_auth_url),
|
||||
start_time, end_time))
|
||||
|
||||
if (options.os_compute_api_version and
|
||||
options.os_compute_api_version != '1.0'):
|
||||
if not os_tenant_name and not os_tenant_id:
|
||||
raise exc.CommandError(_("You must provide a tenant name "
|
||||
"or tenant id via --os-tenant-name, "
|
||||
"--os-tenant-id, env[OS_TENANT_NAME] "
|
||||
"or env[OS_TENANT_ID]"))
|
||||
if not any([args.os_tenant_id, args.os_tenant_name,
|
||||
args.os_project_id, args.os_project_name]):
|
||||
raise exc.CommandError(_("You must provide a project name or"
|
||||
" project id via --os-project-name,"
|
||||
" --os-project-id, env[OS_PROJECT_ID]"
|
||||
" or env[OS_PROJECT_NAME]. You may"
|
||||
" use os-project and os-tenant"
|
||||
" interchangeably."))
|
||||
|
||||
if not os_auth_url:
|
||||
raise exc.CommandError(_("You must provide an auth url "
|
||||
@ -658,6 +706,7 @@ class OpenStackComputeShell(object):
|
||||
timings=args.timings, bypass_url=bypass_url,
|
||||
os_cache=os_cache, http_log_debug=options.debug,
|
||||
cacert=cacert, timeout=timeout,
|
||||
session=keystone_session, auth=keystone_auth,
|
||||
completion_cache=completion_cache)
|
||||
|
||||
# Now check for the password/token of which pieces of the
|
||||
@ -691,7 +740,11 @@ class OpenStackComputeShell(object):
|
||||
# This does a couple of bits which are useful even if we've
|
||||
# got the token + service URL already. It exits fast in that case.
|
||||
if not cliutils.isunauthenticated(args.func):
|
||||
self.cs.authenticate()
|
||||
if not use_session:
|
||||
# Only call authenticate() if Nova auth plugin is used.
|
||||
# If keystone is used, authentication is handled as part
|
||||
# of session.
|
||||
self.cs.authenticate()
|
||||
except exc.Unauthorized:
|
||||
raise exc.CommandError(_("Invalid OpenStack Nova credentials."))
|
||||
except exc.AuthorizationFailure:
|
||||
@ -720,12 +773,13 @@ class OpenStackComputeShell(object):
|
||||
volume_service_name=volume_service_name,
|
||||
timings=args.timings, bypass_url=bypass_url,
|
||||
os_cache=os_cache, http_log_debug=options.debug,
|
||||
session=keystone_session, auth=keystone_auth,
|
||||
cacert=cacert, timeout=timeout)
|
||||
|
||||
args.func(self.cs, args)
|
||||
|
||||
if args.timings:
|
||||
self._dump_timings(self.cs.get_timings())
|
||||
self._dump_timings(self.times + self.cs.get_timings())
|
||||
|
||||
def _dump_timings(self, timings):
|
||||
class Tyme(object):
|
||||
|
@ -16,8 +16,10 @@ import re
|
||||
import sys
|
||||
|
||||
import fixtures
|
||||
from keystoneclient import fixture
|
||||
import mock
|
||||
import prettytable
|
||||
import requests_mock
|
||||
import six
|
||||
from testtools import matchers
|
||||
|
||||
@ -29,23 +31,33 @@ from novaclient.tests import utils
|
||||
FAKE_ENV = {'OS_USERNAME': 'username',
|
||||
'OS_PASSWORD': 'password',
|
||||
'OS_TENANT_NAME': 'tenant_name',
|
||||
'OS_AUTH_URL': 'http://no.where'}
|
||||
'OS_AUTH_URL': 'http://no.where/v2.0'}
|
||||
|
||||
FAKE_ENV2 = {'OS_USER_ID': 'user_id',
|
||||
'OS_PASSWORD': 'password',
|
||||
'OS_TENANT_ID': 'tenant_id',
|
||||
'OS_AUTH_URL': 'http://no.where'}
|
||||
'OS_AUTH_URL': 'http://no.where/v2.0'}
|
||||
|
||||
FAKE_ENV3 = {'OS_USER_ID': 'user_id',
|
||||
'OS_PASSWORD': 'password',
|
||||
'OS_TENANT_ID': 'tenant_id',
|
||||
'OS_AUTH_URL': 'http://no.where',
|
||||
'OS_AUTH_URL': 'http://no.where/v2.0',
|
||||
'NOVA_ENDPOINT_TYPE': 'novaURL',
|
||||
'OS_ENDPOINT_TYPE': 'osURL'}
|
||||
|
||||
|
||||
def _create_ver_list(versions):
|
||||
return {'versions': {'values': versions}}
|
||||
|
||||
|
||||
class ShellTest(utils.TestCase):
|
||||
|
||||
_msg_no_tenant_project = ("You must provide a project name or project"
|
||||
" id via --os-project-name, --os-project-id,"
|
||||
" env[OS_PROJECT_ID] or env[OS_PROJECT_NAME]."
|
||||
" You may use os-project and os-tenant"
|
||||
" interchangeably.")
|
||||
|
||||
def make_env(self, exclude=None, fake_env=FAKE_ENV):
|
||||
env = dict((k, v) for k, v in fake_env.items() if k != exclude)
|
||||
self.useFixture(fixtures.MonkeyPatch('os.environ', env))
|
||||
@ -79,6 +91,12 @@ class ShellTest(utils.TestCase):
|
||||
sys.stderr = orig_stderr
|
||||
return (stdout, stderr)
|
||||
|
||||
def register_keystone_discovery_fixture(self, mreq):
|
||||
v2_url = "http://no.where/v2.0"
|
||||
v2_version = fixture.V2Discovery(v2_url)
|
||||
mreq.register_uri('GET', v2_url, json=_create_ver_list([v2_version]),
|
||||
status_code=200)
|
||||
|
||||
def test_help_unknown_command(self):
|
||||
self.assertRaises(exceptions.CommandError, self.shell, 'help foofoo')
|
||||
|
||||
@ -163,9 +181,7 @@ class ShellTest(utils.TestCase):
|
||||
self.fail('CommandError not raised')
|
||||
|
||||
def test_no_tenant_name(self):
|
||||
required = ('You must provide a tenant name or tenant id'
|
||||
' via --os-tenant-name, --os-tenant-id,'
|
||||
' env[OS_TENANT_NAME] or env[OS_TENANT_ID]')
|
||||
required = self._msg_no_tenant_project
|
||||
self.make_env(exclude='OS_TENANT_NAME')
|
||||
try:
|
||||
self.shell('list')
|
||||
@ -175,14 +191,12 @@ class ShellTest(utils.TestCase):
|
||||
self.fail('CommandError not raised')
|
||||
|
||||
def test_no_tenant_id(self):
|
||||
required = ('You must provide a tenant name or tenant id'
|
||||
' via --os-tenant-name, --os-tenant-id,'
|
||||
' env[OS_TENANT_NAME] or env[OS_TENANT_ID]',)
|
||||
required = self._msg_no_tenant_project
|
||||
self.make_env(exclude='OS_TENANT_ID', fake_env=FAKE_ENV2)
|
||||
try:
|
||||
self.shell('list')
|
||||
except exceptions.CommandError as message:
|
||||
self.assertEqual(required, message.args)
|
||||
self.assertEqual(required, message.args[0])
|
||||
else:
|
||||
self.fail('CommandError not raised')
|
||||
|
||||
@ -200,15 +214,19 @@ class ShellTest(utils.TestCase):
|
||||
self.fail('CommandError not raised')
|
||||
|
||||
@mock.patch('novaclient.client.Client')
|
||||
def test_nova_endpoint_type(self, mock_client):
|
||||
@requests_mock.Mocker()
|
||||
def test_nova_endpoint_type(self, mock_client, m_requests):
|
||||
self.make_env(fake_env=FAKE_ENV3)
|
||||
self.register_keystone_discovery_fixture(m_requests)
|
||||
self.shell('list')
|
||||
client_kwargs = mock_client.call_args_list[0][1]
|
||||
self.assertEqual(client_kwargs['endpoint_type'], 'novaURL')
|
||||
|
||||
@mock.patch('novaclient.client.Client')
|
||||
def test_os_endpoint_type(self, mock_client):
|
||||
@requests_mock.Mocker()
|
||||
def test_os_endpoint_type(self, mock_client, m_requests):
|
||||
self.make_env(exclude='NOVA_ENDPOINT_TYPE', fake_env=FAKE_ENV3)
|
||||
self.register_keystone_discovery_fixture(m_requests)
|
||||
self.shell('list')
|
||||
client_kwargs = mock_client.call_args_list[0][1]
|
||||
self.assertEqual(client_kwargs['endpoint_type'], 'osURL')
|
||||
@ -222,7 +240,8 @@ class ShellTest(utils.TestCase):
|
||||
|
||||
@mock.patch('sys.stdin', side_effect=mock.MagicMock)
|
||||
@mock.patch('getpass.getpass', return_value='password')
|
||||
def test_password(self, mock_getpass, mock_stdin):
|
||||
@requests_mock.Mocker()
|
||||
def test_password(self, mock_getpass, mock_stdin, m_requests):
|
||||
mock_stdin.encoding = "utf-8"
|
||||
|
||||
# default output of empty tables differs depending between prettytable
|
||||
@ -240,6 +259,7 @@ class ShellTest(utils.TestCase):
|
||||
''
|
||||
])
|
||||
self.make_env(exclude='OS_PASSWORD')
|
||||
self.register_keystone_discovery_fixture(m_requests)
|
||||
stdout, stderr = self.shell('list')
|
||||
self.assertEqual((stdout + stderr), ex)
|
||||
|
||||
@ -310,3 +330,17 @@ class ShellTest(utils.TestCase):
|
||||
novaclient.shell.main()
|
||||
except SystemExit as ex:
|
||||
self.assertEqual(ex.code, 130)
|
||||
|
||||
|
||||
class ShellTestKeystoneV3(ShellTest):
|
||||
def make_env(self, exclude=None, fake_env=FAKE_ENV):
|
||||
if 'OS_AUTH_URL' in fake_env:
|
||||
fake_env.update({'OS_AUTH_URL': 'http://no.where/v3'})
|
||||
env = dict((k, v) for k, v in fake_env.items() if k != exclude)
|
||||
self.useFixture(fixtures.MonkeyPatch('os.environ', env))
|
||||
|
||||
def register_keystone_discovery_fixture(self, mreq):
|
||||
v3_url = "http://no.where/v3"
|
||||
v3_version = fixture.V3Discovery(v3_url)
|
||||
mreq.register_uri('GET', v3_url, json=_create_ver_list([v3_version]),
|
||||
status_code=200)
|
||||
|
@ -56,6 +56,7 @@ class ShellTest(utils.TestCase):
|
||||
'NOVA_PROJECT_ID': 'project_id',
|
||||
'OS_COMPUTE_API_VERSION': '1.1',
|
||||
'NOVA_URL': 'http://no.where',
|
||||
'OS_AUTH_URL': 'http://no.where/v2.0',
|
||||
}
|
||||
|
||||
def setUp(self):
|
||||
|
@ -51,6 +51,7 @@ class ShellTest(utils.TestCase):
|
||||
'NOVA_PROJECT_ID': 'project_id',
|
||||
'OS_COMPUTE_API_VERSION': '3',
|
||||
'NOVA_URL': 'http://no.where',
|
||||
'OS_AUTH_URL': 'http://no.where/v2.0',
|
||||
}
|
||||
|
||||
def setUp(self):
|
||||
|
@ -217,11 +217,9 @@ class Client(object):
|
||||
def set_management_url(self, url):
|
||||
self.client.set_management_url(url)
|
||||
|
||||
@client._original_only
|
||||
def get_timings(self):
|
||||
return self.client.get_timings()
|
||||
|
||||
@client._original_only
|
||||
def reset_timings(self):
|
||||
self.client.reset_timings()
|
||||
|
||||
|
@ -33,6 +33,7 @@ from oslo.utils import strutils
|
||||
from oslo.utils import timeutils
|
||||
import six
|
||||
|
||||
from novaclient import client
|
||||
from novaclient import exceptions
|
||||
from novaclient.i18n import _
|
||||
from novaclient.openstack.common import cliutils
|
||||
@ -2759,7 +2760,12 @@ def do_usage(cs, args):
|
||||
if args.tenant:
|
||||
usage = cs.usage.get(args.tenant, start, end)
|
||||
else:
|
||||
usage = cs.usage.get(cs.client.tenant_id, start, end)
|
||||
if isinstance(cs.client, client.SessionClient):
|
||||
auth = cs.client.auth
|
||||
project_id = auth.get_auth_ref(cs.client.session).project_id
|
||||
usage = cs.usage.get(project_id, start, end)
|
||||
else:
|
||||
usage = cs.usage.get(cs.client.tenant_id, start, end)
|
||||
|
||||
print(_("Usage from %(start)s to %(end)s:") %
|
||||
{'start': start.strftime(dateformat),
|
||||
@ -3256,23 +3262,32 @@ def ensure_service_catalog_present(cs):
|
||||
|
||||
def do_endpoints(cs, _args):
|
||||
"""Discover endpoints that get returned from the authenticate services."""
|
||||
ensure_service_catalog_present(cs)
|
||||
if isinstance(cs.client, client.SessionClient):
|
||||
auth = cs.client.auth
|
||||
sc = auth.get_access(cs.client.session).service_catalog
|
||||
for service in sc.get_data():
|
||||
_print_endpoints(service, cs.client.region_name)
|
||||
else:
|
||||
ensure_service_catalog_present(cs)
|
||||
|
||||
catalog = cs.client.service_catalog.catalog
|
||||
region = cs.client.region_name
|
||||
catalog = cs.client.service_catalog.catalog
|
||||
region = cs.client.region_name
|
||||
for service in catalog['access']['serviceCatalog']:
|
||||
_print_endpoints(service, region)
|
||||
|
||||
for service in catalog['access']['serviceCatalog']:
|
||||
name, endpoints = service["name"], service["endpoints"]
|
||||
|
||||
try:
|
||||
endpoint = _get_first_endpoint(endpoints, region)
|
||||
utils.print_dict(endpoint, name)
|
||||
except LookupError:
|
||||
print(_("WARNING: %(service)s has no endpoint in %(region)s! "
|
||||
"Available endpoints for this service:") %
|
||||
{'service': name, 'region': region})
|
||||
for other_endpoint in endpoints:
|
||||
utils.print_dict(other_endpoint, name)
|
||||
def _print_endpoints(service, region):
|
||||
name, endpoints = service["name"], service["endpoints"]
|
||||
|
||||
try:
|
||||
endpoint = _get_first_endpoint(endpoints, region)
|
||||
utils.print_dict(endpoint, name)
|
||||
except LookupError:
|
||||
print(_("WARNING: %(service)s has no endpoint in %(region)s! "
|
||||
"Available endpoints for this service:") %
|
||||
{'service': name, 'region': region})
|
||||
for other_endpoint in endpoints:
|
||||
utils.print_dict(other_endpoint, name)
|
||||
|
||||
|
||||
def _get_first_endpoint(endpoints, region):
|
||||
@ -3298,11 +3313,19 @@ def _get_first_endpoint(endpoints, region):
|
||||
help=_('wrap PKI tokens to a specified length, or 0 to disable'))
|
||||
def do_credentials(cs, _args):
|
||||
"""Show user credentials returned from auth."""
|
||||
ensure_service_catalog_present(cs)
|
||||
catalog = cs.client.service_catalog.catalog
|
||||
utils.print_dict(catalog['access']['user'], "User Credentials",
|
||||
wrap=int(_args.wrap))
|
||||
utils.print_dict(catalog['access']['token'], "Token", wrap=int(_args.wrap))
|
||||
if isinstance(cs.client, client.SessionClient):
|
||||
auth = cs.client.auth
|
||||
sc = auth.get_access(cs.client.session).service_catalog
|
||||
utils.print_dict(sc.catalog['user'], 'User Credentials',
|
||||
wrap=int(_args.wrap))
|
||||
utils.print_dict(sc.get_token(), 'Token', wrap=int(_args.wrap))
|
||||
else:
|
||||
ensure_service_catalog_present(cs)
|
||||
catalog = cs.client.service_catalog.catalog
|
||||
utils.print_dict(catalog['access']['user'], "User Credentials",
|
||||
wrap=int(_args.wrap))
|
||||
utils.print_dict(catalog['access']['token'], "Token",
|
||||
wrap=int(_args.wrap))
|
||||
|
||||
|
||||
@utils.arg('server', metavar='<server>', help=_('Name or ID of server.'))
|
||||
|
@ -174,11 +174,9 @@ class Client(object):
|
||||
def set_management_url(self, url):
|
||||
self.client.set_management_url(url)
|
||||
|
||||
@client._original_only
|
||||
def get_timings(self):
|
||||
return self.client.get_timings()
|
||||
|
||||
@client._original_only
|
||||
def reset_timings(self):
|
||||
self.client.reset_timings()
|
||||
|
||||
|
@ -31,6 +31,7 @@ from oslo.utils import strutils
|
||||
from oslo.utils import timeutils
|
||||
import six
|
||||
|
||||
from novaclient import client
|
||||
from novaclient import exceptions
|
||||
from novaclient.i18n import _
|
||||
from novaclient.openstack.common import cliutils
|
||||
@ -2140,7 +2141,12 @@ def do_usage(cs, args):
|
||||
if args.tenant:
|
||||
usage = cs.usage.get(args.tenant, start, end)
|
||||
else:
|
||||
usage = cs.usage.get(cs.client.tenant_id, start, end)
|
||||
if isinstance(cs.client, client.SessionClient):
|
||||
auth = cs.client.auth
|
||||
project_id = auth.get_auth_ref(cs.client.session).project_id
|
||||
usage = cs.usage.get(project_id, start, end)
|
||||
else:
|
||||
usage = cs.usage.get(cs.client.tenant_id, start, end)
|
||||
|
||||
print("Usage from %s to %s:" % (start.strftime(dateformat),
|
||||
end.strftime(dateformat)))
|
||||
@ -2692,23 +2698,33 @@ def ensure_service_catalog_present(cs):
|
||||
|
||||
def do_endpoints(cs, _args):
|
||||
"""Discover endpoints that get returned from the authenticate services."""
|
||||
ensure_service_catalog_present(cs)
|
||||
if isinstance(cs.client, client.SessionClient):
|
||||
auth = cs.client.auth
|
||||
sc = auth.get_Access(cs.client.session).service_catalog
|
||||
for service in sc.get_data():
|
||||
_print_endpoints(service, cs.client.region_name)
|
||||
else:
|
||||
ensure_service_catalog_present(cs)
|
||||
|
||||
catalog = cs.client.service_catalog.catalog
|
||||
region = cs.client.region_name
|
||||
catalog = cs.client.service_catalog.catalog
|
||||
region = cs.client.region_name
|
||||
|
||||
for service in catalog['access']['serviceCatalog']:
|
||||
name, endpoints = service["name"], service["endpoints"]
|
||||
for service in catalog['access']['serviceCatalog']:
|
||||
_print_endpoints(service, region)
|
||||
|
||||
try:
|
||||
endpoint = _get_first_endpoint(endpoints, region)
|
||||
utils.print_dict(endpoint, name)
|
||||
except LookupError:
|
||||
print(_("WARNING: %(service)s has no endpoint in %(region)s! "
|
||||
"Available endpoints for this service:") %
|
||||
{'service': name, 'region': region})
|
||||
for other_endpoint in endpoints:
|
||||
utils.print_dict(other_endpoint, name)
|
||||
|
||||
def _print_endpoints(service, region):
|
||||
name, endpoints = service["name"], service["endpoints"]
|
||||
|
||||
try:
|
||||
endpoint = _get_first_endpoint(endpoints, region)
|
||||
utils.print_dict(endpoint, name)
|
||||
except LookupError:
|
||||
print(_("WARNING: %(service)s has no endpoint in %(region)s! "
|
||||
"Available endpoints for this service:") %
|
||||
{'service': name, 'region': region})
|
||||
for other_endpoint in endpoints:
|
||||
utils.print_dict(other_endpoint, name)
|
||||
|
||||
|
||||
def _get_first_endpoint(endpoints, region):
|
||||
@ -2734,11 +2750,19 @@ def _get_first_endpoint(endpoints, region):
|
||||
help='wrap PKI tokens to a specified length, or 0 to disable')
|
||||
def do_credentials(cs, _args):
|
||||
"""Show user credentials returned from auth."""
|
||||
ensure_service_catalog_present(cs)
|
||||
catalog = cs.client.service_catalog.catalog
|
||||
utils.print_dict(catalog['access']['user'], "User Credentials",
|
||||
wrap=int(_args.wrap))
|
||||
utils.print_dict(catalog['access']['token'], "Token", wrap=int(_args.wrap))
|
||||
if isinstance(cs.client, client.SessionClient):
|
||||
auth = cs.client.auth
|
||||
sc = auth.get_access(cs.client.session).service_catalog
|
||||
utils.print_dict(sc.catalog['user'], 'User Credentials',
|
||||
wrap=int(_args.wrap))
|
||||
utils.print_dict(sc.get_token(), 'Token', wrap=int(_args.wrap))
|
||||
else:
|
||||
ensure_service_catalog_present(cs)
|
||||
catalog = cs.client.service_catalog.catalog
|
||||
utils.print_dict(catalog['access']['user'], "User Credentials",
|
||||
wrap=int(_args.wrap))
|
||||
utils.print_dict(catalog['access']['token'], "Token",
|
||||
wrap=int(_args.wrap))
|
||||
|
||||
|
||||
def do_extension_list(cs, _args):
|
||||
|
Loading…
x
Reference in New Issue
Block a user