summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--novaclient/keystone/shell.py99
-rw-r--r--novaclient/shell.py59
-rw-r--r--novaclient/utils.py21
-rw-r--r--setup.py3
4 files changed, 159 insertions, 23 deletions
diff --git a/novaclient/keystone/shell.py b/novaclient/keystone/shell.py
new file mode 100644
index 00000000..18299cd6
--- /dev/null
+++ b/novaclient/keystone/shell.py
@@ -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)
diff --git a/novaclient/shell.py b/novaclient/shell.py
index 989b6ef1..b46a174d 100644
--- a/novaclient/shell.py
+++ b/novaclient/shell.py
@@ -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 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 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 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[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 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:
diff --git a/novaclient/utils.py b/novaclient/utils.py
index 083620ad..9c6dbd07 100644
--- a/novaclient/utils.py
+++ b/novaclient/utils.py
@@ -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)
diff --git a/setup.py b/setup.py
index c209667d..701295c3 100644
--- a/setup.py
+++ b/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",