Merge "Add Support for Keystone V3 CLI"

This commit is contained in:
Jenkins
2014-11-24 11:59:00 +00:00
committed by Gerrit Code Review
3 changed files with 214 additions and 62 deletions

View File

@@ -13,6 +13,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
from keystoneclient import adapter
from keystoneclient.v2_0 import client as keystone_client_v2
from keystoneclient.v3 import client as keystone_client_v3
@@ -33,26 +34,38 @@ class Client(object):
def __init__(self, username=None, api_key=None, project_id=None,
project_name=None, auth_url=None, sahara_url=None,
endpoint_type='publicURL', service_type='data_processing',
input_auth_token=None):
service_name=None, region_name=None,
input_auth_token=None, session=None, auth=None):
keystone = None
sahara_catalog_url = sahara_url
if not input_auth_token:
keystone = self.get_keystone_client(username=username,
api_key=api_key,
auth_url=auth_url,
project_id=project_id,
project_name=project_name)
input_auth_token = keystone.auth_token
if session:
keystone = adapter.LegacyJsonAdapter(
session=session,
auth=auth,
interface=endpoint_type,
service_type=service_type,
service_name=service_name,
region_name=region_name)
input_auth_token = keystone.session.get_token(auth)
sahara_catalog_url = keystone.session.get_endpoint(
auth, interface=endpoint_type, service_type=service_type)
else:
keystone = self.get_keystone_client(
username=username,
api_key=api_key,
auth_url=auth_url,
project_id=project_id,
project_name=project_name)
input_auth_token = keystone.auth_token
if not input_auth_token:
raise RuntimeError("Not Authorized")
sahara_catalog_url = sahara_url
if not sahara_url:
keystone = self.get_keystone_client(username=username,
api_key=api_key,
auth_url=auth_url,
token=input_auth_token,
project_id=project_id,
project_name=project_name)
if not sahara_catalog_url:
catalog = keystone.service_catalog.get_endpoints(service_type)
if service_type not in catalog:
service_type = service_type.replace('-', '_')
@@ -86,10 +99,12 @@ class Client(object):
def get_keystone_client(self, username=None, api_key=None, auth_url=None,
token=None, project_id=None, project_name=None):
if not auth_url:
raise RuntimeError("No auth url specified")
imported_client = (keystone_client_v2 if "v2.0" in auth_url
else keystone_client_v3)
raise RuntimeError("No auth url specified")
if not getattr(self, "keystone_client", None):
imported_client = (keystone_client_v2 if "v2.0" in auth_url
else keystone_client_v3)
self.keystone_client = imported_client.Client(
username=username,
password=api_key,

View File

@@ -47,6 +47,11 @@ try:
except ImportError:
pass
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
from saharaclient.api import client
from saharaclient.api import shell as shell_api
from saharaclient.openstack.common.apiclient import auth
@@ -251,6 +256,7 @@ class OpenStackSaharaShell(object):
help="Use the auth token cache. Defaults to False "
"if env[OS_CACHE] is not set.")
# TODO(mattf) - add get_timings support to Client
# parser.add_argument('--timings',
# default=False,
@@ -264,11 +270,6 @@ class OpenStackSaharaShell(object):
# type=positive_non_zero_float,
# help="Set HTTP call timeout (in seconds)")
parser.add_argument('--os-tenant-id',
metavar='<auth-tenant-id>',
default=cliutils.env('OS_TENANT_ID'),
help='Defaults to env[OS_TENANT_ID].')
# NA
# parser.add_argument('--os-region-name',
# metavar='<region-name>',
@@ -324,22 +325,6 @@ class OpenStackSaharaShell(object):
parser.add_argument('--sahara_api_version',
help=argparse.SUPPRESS)
parser.add_argument('--os-cacert',
metavar='<ca-certificate>',
default=cliutils.env('OS_CACERT', default=None),
help='Specify a CA bundle file to use in '
'verifying a TLS (https) server certificate. '
'Defaults to env[OS_CACERT].')
# NA
# parser.add_argument('--insecure',
# default=utils.env('NOVACLIENT_INSECURE', default=False),
# action='store_true',
# help="Explicitly allow novaclient to perform \"insecure\" "
# "SSL (https) requests. The server's certificate will "
# "not be verified against any certificate authorities. "
# "This option should be used with caution.")
parser.add_argument('--bypass-url',
metavar='<bypass-url>',
default=cliutils.env('BYPASS_URL', default=None),
@@ -349,8 +334,25 @@ class OpenStackSaharaShell(object):
parser.add_argument('--bypass_url',
help=argparse.SUPPRESS)
# The auth-system-plugins might require some extra options
auth.load_auth_system_opts(parser)
parser.add_argument('--os-tenant-name',
default=cliutils.env('OS_TENANT_NAME'),
help='Defaults to env[OS_TENANT_NAME].')
parser.add_argument('--os-tenant-id',
default=cliutils.env('OS_TENANT_ID'),
help='Defaults to env[OS_TENANT_ID].')
parser.add_argument('--os-auth-system',
default=cliutils.env('OS_AUTH_SYSTEM'),
help='Defaults to env[OS_AUTH_SYSTEM].')
parser.add_argument('--os-auth-token',
default=cliutils.env('OS_AUTH_TOKEN'),
help='Defaults to env[OS_AUTH_TOKEN].')
# Use Keystoneclient API to parse authentication arguments
session.Session.register_cli_options(parser)
identity.Password.register_argparse_arguments(parser)
return parser
@@ -418,12 +420,27 @@ class OpenStackSaharaShell(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()
(options, args) = parser.parse_known_args(argv)
self.setup_debugging(options.debug)
self.options = options
# NOTE(dtroyer): Hackery to handle --endpoint_type due to argparse
# thinking usage-list --end is ambiguous; but it
@@ -502,12 +519,6 @@ class OpenStackSaharaShell(object):
"via either --os-username or "
"env[OS_USERNAME]")
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 os_auth_url:
if os_auth_system and os_auth_system != 'keystone':
os_auth_url = auth_plugin.get_auth_url()
@@ -574,21 +585,63 @@ class OpenStackSaharaShell(object):
# self.cs.client.password = os_password
# self.cs.client.keyring_saver = helper
# NA
# try:
# if not utils.isunauthenticated(args.func):
# self.cs.authenticate()
# except exc.Unauthorized:
# raise exc.CommandError("Invalid OpenStack Sahara credentials.")
# except exc.AuthorizationFailure:
# raise exc.CommandError("Unable to authorize user")
# V3 stuff
project_info_provided = (self.options.os_tenant_name or
self.options.os_tenant_id or
(self.options.os_project_name and
(self.options.os_project_domain_name or
self.options.os_project_domain_id)) or
self.options.os_project_id)
if (not project_info_provided):
raise exc.CommandError(
("You must provide a tenant_name, tenant_id, "
"project_id or project_name (with "
"project_domain_name or project_domain_id) via "
" --os-tenant-name (env[OS_TENANT_NAME]),"
" --os-tenant-id (env[OS_TENANT_ID]),"
" --os-project-id (env[OS_PROJECT_ID])"
" --os-project-name (env[OS_PROJECT_NAME]),"
" --os-project-domain-id "
"(env[OS_PROJECT_DOMAIN_ID])"
" --os-project-domain-name "
"(env[OS_PROJECT_DOMAIN_NAME])"))
if not os_auth_url:
raise exc.CommandError(
"You must provide an auth url "
"via either --os-auth-url or env[OS_AUTH_URL]")
keystone_session = None
keystone_auth = None
if not auth_plugin:
project_id = args.os_project_id or args.os_tenant_id
project_name = args.os_project_name or args.os_tenant_name
keystone_session = (session.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)
self.cs = client.Client(username=os_username,
api_key=os_password,
project_id=os_tenant_id,
project_name=os_tenant_name,
auth_url=os_auth_url,
sahara_url=bypass_url)
sahara_url=bypass_url,
session=keystone_session,
auth=keystone_auth)
args.func(self.cs, args)

View File

@@ -170,9 +170,19 @@ 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 = (
'You must provide a tenant_name, tenant_id, '
'project_id or project_name (with '
'project_domain_name or project_domain_id) via '
' --os-tenant-name (env[OS_TENANT_NAME]),'
' --os-tenant-id (env[OS_TENANT_ID]),'
' --os-project-id (env[OS_PROJECT_ID])'
' --os-project-name (env[OS_PROJECT_NAME]),'
' --os-project-domain-id '
'(env[OS_PROJECT_DOMAIN_ID])'
' --os-project-domain-name '
'(env[OS_PROJECT_DOMAIN_NAME])',
)
self.make_env(exclude='OS_TENANT_NAME')
try:
self.shell('plugin-list')
@@ -182,9 +192,19 @@ 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 = (
'You must provide a tenant_name, tenant_id, '
'project_id or project_name (with '
'project_domain_name or project_domain_id) via '
' --os-tenant-name (env[OS_TENANT_NAME]),'
' --os-tenant-id (env[OS_TENANT_ID]),'
' --os-project-id (env[OS_PROJECT_ID])'
' --os-project-name (env[OS_PROJECT_NAME]),'
' --os-project-domain-id '
'(env[OS_PROJECT_DOMAIN_ID])'
' --os-project-domain-name '
'(env[OS_PROJECT_DOMAIN_NAME])',
)
self.make_env(exclude='OS_TENANT_ID', fake_env=FAKE_ENV2)
try:
self.shell('plugin-list')
@@ -281,3 +301,67 @@ class ShellTest(utils.TestCase):
self.make_env()
stdout, stderr = self.shell('image-list')
self.assertEqual(ex, (stdout + stderr))
class ShellTestKeystoneV3(ShellTest):
FAKE_V3_ENV = {'OS_USERNAME': 'username',
'OS_PASSWORD': 'password',
'OS_PROJECT_NAME': 'project_name',
'OS_PROJECT_DOMAIN_NAME': 'project_domain_name',
'OS_USER_DOMAIN_NAME': 'user_domain_name',
'OS_AUTH_URL': 'http://no.where/v3'}
version_id = u'v3'
links = [{u'href': u'http://no.where/v3', u'rel': u'self'}]
def make_env(self, exclude=None, fake_env=FAKE_V3_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 test_no_tenant_name(self):
# In V3, tenant_name = project_name
required = (
'You must provide a tenant_name, tenant_id, '
'project_id or project_name (with '
'project_domain_name or project_domain_id) via '
' --os-tenant-name (env[OS_TENANT_NAME]),'
' --os-tenant-id (env[OS_TENANT_ID]),'
' --os-project-id (env[OS_PROJECT_ID])'
' --os-project-name (env[OS_PROJECT_NAME]),'
' --os-project-domain-id '
'(env[OS_PROJECT_DOMAIN_ID])'
' --os-project-domain-name '
'(env[OS_PROJECT_DOMAIN_NAME])',
)
self.make_env(exclude='OS_PROJECT_NAME')
try:
self.shell('plugin-list')
except exceptions.CommandError as message:
self.assertEqual(required, message.args)
else:
self.fail('CommandError not raised')
def test_job_list(self):
expected = '\n'.join([
'+----+------------+--------+',
'| id | cluster_id | status |',
'+----+------------+--------+',
'+----+------------+--------+',
''
])
mock_session_class_name = 'keystoneclient.adapter.LegacyJsonAdapter'
mock_job_executions_class_name = (
'saharaclient.api.job_executions.JobExecutionsManager')
with mock.patch(mock_session_class_name) as mock_session:
with mock.patch(mock_job_executions_class_name):
ms = mock_session.return_value
ms.session.get_endpoint.return_value = 'http://no.where'
self.make_env()
stdout, stderr = self.shell('job-list')
self.assertEqual((stdout + stderr), expected)