Add 'discover' command for Keystone discovery and version listing
Added @unauthenticated decorator to mark subcommands that do not need authentication. And checks to skip authentication for these commands. Added novaclient.keystone to setup.py Change-Id: Id2fd60af305c30a950bdbae8f897192bfae4d797
This commit is contained in:
parent
e20dcd8cd7
commit
49284dc5cd
99
novaclient/keystone/shell.py
Normal file
99
novaclient/keystone/shell.py
Normal file
@ -0,0 +1,99 @@
|
||||
# Copyright 2010 Jacob Kaplan-Moss
|
||||
|
||||
# Copyright 2011 OpenStack LLC.
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import httplib2
|
||||
import urllib
|
||||
import urlparse
|
||||
|
||||
try:
|
||||
import json
|
||||
except ImportError:
|
||||
import simplejson as json
|
||||
|
||||
# Python 2.5 compat fix
|
||||
if not hasattr(urlparse, 'parse_qsl'):
|
||||
import cgi
|
||||
urlparse.parse_qsl = cgi.parse_qsl
|
||||
|
||||
|
||||
from novaclient import exceptions
|
||||
from novaclient import utils
|
||||
from novaclient import client
|
||||
|
||||
|
||||
@utils.unauthenticated
|
||||
def do_discover(cs, args):
|
||||
"""
|
||||
Discover Keystone servers and show authentication protocols supported.
|
||||
|
||||
Usage:
|
||||
$ nova discover
|
||||
Keystone found at http://localhost:35357
|
||||
- supports version v2.0 (beta) here http://localhost:35357/v2.0
|
||||
Keystone found at https://openstack.org/
|
||||
- supports version v1.0 (DEPRECATED) here https://openstack.org/v1.0
|
||||
- supports version v1.1 (CURRENT) here https://openstack.org/v1.1
|
||||
- supports version v2.0 (BETA) here https://openstack.org/v2.0
|
||||
"""
|
||||
_local_keystone_exists()
|
||||
_check_keystone_versions(cs.client.auth_url)
|
||||
|
||||
|
||||
def _local_keystone_exists():
|
||||
return _check_keystone_versions("http://localhost:35357")
|
||||
|
||||
|
||||
def _check_keystone_versions(url):
|
||||
try:
|
||||
httpclient = client.HTTPClient(user=None, password=None,
|
||||
projectid=None, auth_url=None)
|
||||
resp, body = httpclient.request(url, "GET",
|
||||
headers={'Accept': 'application/json'})
|
||||
if resp.status in (200, 204): # in some cases we get No Content
|
||||
try:
|
||||
print "Keystone found at %s" % url
|
||||
if 'version' in body:
|
||||
version = body['version']
|
||||
# Stable/diablo incorrect format
|
||||
_display_version_info(version, url)
|
||||
return True
|
||||
if 'versions' in body:
|
||||
# Correct format
|
||||
for version in body['versions']['values']:
|
||||
_display_version_info(version, url)
|
||||
return True
|
||||
print "Unrecognized response from %s" % url
|
||||
except KeyError:
|
||||
raise exceptions.AuthorizationFailure()
|
||||
elif resp.status == 305:
|
||||
return _check_keystone_versions(resp['location'])
|
||||
else:
|
||||
raise exceptions.from_response(resp, body)
|
||||
except:
|
||||
return False
|
||||
|
||||
|
||||
def _display_version_info(version, url):
|
||||
id = version['id']
|
||||
status = version['status']
|
||||
ref = urlparse.urljoin(url, id)
|
||||
if 'links' in version:
|
||||
for link in version['links']:
|
||||
if link['rel'] == 'self':
|
||||
ref = link['href']
|
||||
break
|
||||
print " - supports version %s (%s) here %s" % (id, status, ref)
|
@ -29,6 +29,7 @@ from novaclient import base
|
||||
from novaclient import exceptions as exc
|
||||
from novaclient import utils
|
||||
from novaclient.v1_1 import shell as shell_v1_1
|
||||
from novaclient.keystone import shell as shell_keystone
|
||||
|
||||
|
||||
def env(*vars):
|
||||
@ -119,6 +120,7 @@ class OpenStackComputeShell(object):
|
||||
actions_module = shell_v1_1
|
||||
|
||||
self._find_actions(subparsers, actions_module)
|
||||
self._find_actions(subparsers, shell_keystone)
|
||||
self._find_actions(subparsers, self)
|
||||
|
||||
for _, _, ext_module in extensions:
|
||||
@ -229,27 +231,39 @@ class OpenStackComputeShell(object):
|
||||
#FIXME(usrleon): Here should be restrict for project id same as
|
||||
# for username or password but for compatibility it is not.
|
||||
|
||||
if not user:
|
||||
raise exc.CommandError("You must provide a username, either "
|
||||
"via --username or via "
|
||||
"env[OS_USER_NAME]")
|
||||
if not utils.isunauthenticated(args.func):
|
||||
if not user:
|
||||
raise exc.CommandError("You must provide a username, either "
|
||||
"via --username or via "
|
||||
"env[NOVA_USERNAME]")
|
||||
|
||||
if not password:
|
||||
if not apikey:
|
||||
raise exc.CommandError("You must provide a password, either "
|
||||
"via --password or via env[OS_PASSWORD]")
|
||||
else:
|
||||
password = apikey
|
||||
if not password:
|
||||
if not apikey:
|
||||
raise exc.CommandError("You must provide a password, "
|
||||
"either via --password or via env[NOVA_PASSWORD]")
|
||||
else:
|
||||
password = apikey
|
||||
|
||||
if not projectid:
|
||||
raise exc.CommandError("You must provide an projectid, either "
|
||||
"via --projectid or via "
|
||||
"env[OS_TENANT_NAME]")
|
||||
if not projectid:
|
||||
raise exc.CommandError("You must provide an projectid, either "
|
||||
"via --projectid or via "
|
||||
"env[OS_TENANT_NAME]")
|
||||
|
||||
if not url:
|
||||
raise exc.CommandError("You must provide a auth url, either "
|
||||
"via --url or via "
|
||||
"env[OS_AUTH_URL]")
|
||||
if not url:
|
||||
raise exc.CommandError("You must provide a auth url, either "
|
||||
"via --url or via "
|
||||
"env[OS_AUTH_URL]")
|
||||
|
||||
if options.version and options.version != '1.0':
|
||||
if not projectid:
|
||||
raise exc.CommandError("You must provide an projectid, "
|
||||
"either via --projectid or via "
|
||||
"env[NOVA_PROJECT_ID")
|
||||
|
||||
if not url:
|
||||
raise exc.CommandError("You must provide a auth url,"
|
||||
" either via --url or via "
|
||||
"env[NOVA_URL")
|
||||
|
||||
self.cs = self.get_api_class(options.version)(user, password,
|
||||
projectid, url, insecure,
|
||||
@ -258,7 +272,8 @@ class OpenStackComputeShell(object):
|
||||
extensions=extensions)
|
||||
|
||||
try:
|
||||
self.cs.authenticate()
|
||||
if not utils.isunauthenticated(args.func):
|
||||
self.cs.authenticate()
|
||||
except exc.Unauthorized:
|
||||
raise exc.CommandError("Invalid OpenStack Nova credentials.")
|
||||
except exc.AuthorizationFailure:
|
||||
|
@ -15,6 +15,27 @@ def arg(*args, **kwargs):
|
||||
return _decorator
|
||||
|
||||
|
||||
def unauthenticated(f):
|
||||
"""
|
||||
Adds 'unauthenticated' attribute to decorated function.
|
||||
Usage:
|
||||
@unauthenticated
|
||||
def mymethod(f):
|
||||
...
|
||||
"""
|
||||
f.unauthenticated = True
|
||||
return f
|
||||
|
||||
|
||||
def isunauthenticated(f):
|
||||
"""
|
||||
Checks to see if the function is marked as not requiring authentication
|
||||
with the @unauthenticated decorator. Returns True if decorator is
|
||||
set to True, False otherwise.
|
||||
"""
|
||||
return getattr(f, 'unauthenticated', False)
|
||||
|
||||
|
||||
def pretty_choice_list(l):
|
||||
return ', '.join("'%s'" % i for i in l)
|
||||
|
||||
|
3
setup.py
3
setup.py
@ -37,7 +37,8 @@ setuptools.setup(
|
||||
long_description=read_file("README.rst"),
|
||||
license="Apache License, Version 2.0",
|
||||
url="https://github.com/openstack/python-novaclient",
|
||||
packages=["novaclient", "novaclient.v1_1", "novaclient.v1_1.contrib"],
|
||||
packages=["novaclient", "novaclient.v1_1", "novaclient.v1_1.contrib",
|
||||
"novaclient.keystone"],
|
||||
install_requires=requirements,
|
||||
tests_require=["nose", "mock"],
|
||||
test_suite="nose.collector",
|
||||
|
Loading…
Reference in New Issue
Block a user