summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFabio Giannetti <fabio.giannetti@hp.com>2014-05-28 18:18:55 -0700
committerFabio Giannetti <fabio.giannetti@hp.com>2014-06-26 09:39:38 -0700
commit6082ae31ed260520079a58cb2f0e4d3b3915d7da (patch)
tree1b9a2cadd978c7860fed834544ad969248a79b8e
parente5cd3b26b7b4dbf86b9665a459db50f4be93dd34 (diff)
downloadpython-ceilometerclient-6082ae31ed260520079a58cb2f0e4d3b3915d7da.tar.gz
Update python-ceilometerclient to support Keystone V3 API
Keystone is now deprecating the V2 API in favor of the V3 API. The ceilometer client is now using the keystone session to delegate the discovery of the version that is going to be used, this eliminates the need of updating the client every time there is a new API version. DocImpact blueprint support-keystone-v3-api Change-Id: I6ebacce7adf70f24bdede9b920853ab9851071cf
-rw-r--r--ceilometerclient/client.py203
-rw-r--r--ceilometerclient/shell.py233
-rw-r--r--ceilometerclient/tests/test_client.py2
-rw-r--r--ceilometerclient/tests/test_shell.py68
4 files changed, 364 insertions, 142 deletions
diff --git a/ceilometerclient/client.py b/ceilometerclient/client.py
index 7bfe1a6..b66e547 100644
--- a/ceilometerclient/client.py
+++ b/ceilometerclient/client.py
@@ -10,38 +10,133 @@
# License for the specific language governing permissions and limitations
# under the License.
-from keystoneclient.v2_0 import client as ksclient
+from keystoneclient.auth.identity import v2 as v2_auth
+from keystoneclient.auth.identity import v3 as v3_auth
+from keystoneclient import discover
+from keystoneclient import session
import six
from ceilometerclient.common import utils
-
-
-def _get_ksclient(**kwargs):
- """Get an endpoint and auth token from Keystone.
-
- :param kwargs: keyword args containing credentials:
- * username: name of user
- * password: user's password
- * auth_url: endpoint to authenticate against
- * cacert: path of CA TLS certificate
- * insecure: allow insecure SSL (no cert verification)
- * tenant_{name|id}: name or ID of tenant
- """
- return ksclient.Client(username=kwargs.get('username'),
- password=kwargs.get('password'),
- tenant_id=kwargs.get('tenant_id'),
- tenant_name=kwargs.get('tenant_name'),
- auth_url=kwargs.get('auth_url'),
- region_name=kwargs.get('region_name'),
- cacert=kwargs.get('cacert'),
- insecure=kwargs.get('insecure'))
-
-
-def _get_endpoint(client, **kwargs):
- """Get an endpoint using the provided keystone client."""
- return client.service_catalog.url_for(
- service_type=kwargs.get('service_type') or 'metering',
- endpoint_type=kwargs.get('endpoint_type') or 'publicURL')
+from ceilometerclient import exc
+
+
+def _get_keystone_session(**kwargs):
+ # TODO(fabgia): the heavy lifting here should be really done by Keystone.
+ # Unfortunately Keystone does not support a richer method to perform
+ # discovery and return a single viable URL. A bug against Keystone has
+ # been filed: https://bugs.launchpad.net/pyhton-keystoneclient/+bug/1330677
+
+ # first create a Keystone session
+ cacert = kwargs.pop('cacert', None)
+ cert = kwargs.pop('cert', None)
+ key = kwargs.pop('key', None)
+ insecure = kwargs.pop('insecure', False)
+ auth_url = kwargs.pop('auth_url', None)
+ project_id = kwargs.pop('project_id', None)
+ project_name = kwargs.pop('project_name', None)
+
+ if insecure:
+ verify = False
+ else:
+ verify = cacert or True
+
+ if cert and key:
+ # passing cert and key together is deprecated in favour of the
+ # requests lib form of having the cert and key as a tuple
+ cert = (cert, key)
+
+ # create the keystone client session
+ ks_session = session.Session(verify=verify, cert=cert)
+
+ try:
+ # discover the supported keystone versions using the auth endpoint url
+ ks_discover = discover.Discover(session=ks_session, auth_url=auth_url)
+ # Determine which authentication plugin to use.
+ v2_auth_url = ks_discover.url_for('2.0')
+ v3_auth_url = ks_discover.url_for('3.0')
+ except Exception:
+ raise exc.CommandError('Unable to determine the Keystone version '
+ 'to authenticate with using the given '
+ 'auth_url: %s' % auth_url)
+
+ username = kwargs.pop('username', None)
+ user_id = kwargs.pop('user_id', None)
+ user_domain_name = kwargs.pop('user_domain_name', None)
+ user_domain_id = kwargs.pop('user_domain_id', None)
+ project_domain_name = kwargs.pop('project_domain_name', None)
+ project_domain_id = kwargs.pop('project_domain_id', None)
+ auth = None
+
+ if v3_auth_url and v2_auth_url:
+ # the auth_url does not have the versions specified
+ # e.g. http://no.where:5000
+ # Keystone will return both v2 and v3 as viable options
+ # but we need to decide based on the arguments passed
+ # what version is callable
+ if (user_domain_name or user_domain_id or project_domain_name or
+ project_domain_id):
+ # domain is supported only in v3
+ auth = v3_auth.Password(
+ v3_auth_url,
+ username=username,
+ user_id=user_id,
+ user_domain_name=user_domain_name,
+ user_domain_id=user_domain_id,
+ project_domain_name=project_domain_name,
+ project_domain_id=project_domain_id,
+ **kwargs)
+ else:
+ # no domain, then use v2
+ auth = v2_auth.Password(
+ v2_auth_url,
+ username,
+ kwargs.pop('password', None),
+ tenant_id=project_id,
+ tenant_name=project_name)
+ elif v3_auth_url:
+ # the auth_url as v3 specified
+ # e.g. http://no.where:5000/v3
+ # Keystone will return only v3 as viable option
+ auth = v3_auth.Password(
+ v3_auth_url,
+ username=username,
+ user_id=user_id,
+ user_domain_name=user_domain_name,
+ user_domain_id=user_domain_id,
+ project_domain_name=project_domain_name,
+ project_domain_id=project_domain_id,
+ **kwargs)
+ elif v2_auth_url:
+ # the auth_url as v2 specified
+ # e.g. http://no.where:5000/v2.0
+ # Keystone will return only v2 as viable option
+ auth = v2_auth.Password(
+ v2_auth_url,
+ username,
+ kwargs.pop('password', None),
+ tenant_id=project_id,
+ tenant_name=project_name)
+ else:
+ raise exc.CommandError('Unable to determine the Keystone version '
+ 'to authenticate with using the given '
+ 'auth_url.')
+
+ ks_session.auth = auth
+ return ks_session
+
+
+def _get_endpoint(ks_session, **kwargs):
+ """Get an endpoint using the provided keystone session."""
+
+ # set service specific endpoint types
+ endpoint_type = kwargs.get('endpoint_type') or 'publicURL'
+ service_type = kwargs.get('service_type') or 'metering'
+
+ endpoint = ks_session.get_endpoint(service_type=service_type,
+ endpoint_type=endpoint_type,
+ region_name=kwargs.get('region_name'))
+
+ return endpoint
def get_client(api_version, **kwargs):
@@ -55,10 +150,19 @@ def get_client(api_version, **kwargs):
or:
* os_username: name of user
* os_password: user's password
+ * os_user_id: user's id
+ * os_user_domain_id: the domain id of the user
+ * os_user_domain_name: the domain name of the user
+ * os_project_id: the user project id
+ * os_tenant_id: V2 alternative to os_project_id
+ * os_project_name: the user project name
+ * os_tenant_name: V2 alternative to os_project_name
+ * os_project_domain_name: domain name for the user project
+ * os_project_domain_id: domain id for the user project
* os_auth_url: endpoint to authenticate against
- * os_cacert: path of CA TLS certificate
+ * os_cert|os_cacert: path of CA TLS certificate
+ * os_key: SSL private key
* insecure: allow insecure SSL (no cert verification)
- * os_tenant_{name|id}: name or ID of tenant
"""
token = kwargs.get('os_auth_token')
if token and not six.callable(token):
@@ -66,36 +170,41 @@ def get_client(api_version, **kwargs):
if token and kwargs.get('ceilometer_url'):
endpoint = kwargs.get('ceilometer_url')
- elif (kwargs.get('os_username') and
- kwargs.get('os_password') and
- kwargs.get('os_auth_url') and
- (kwargs.get('os_tenant_id') or kwargs.get('os_tenant_name'))):
-
+ else:
+ project_id = kwargs.get('os_project_id') or kwargs.get('os_tenant_id')
+ project_name = (kwargs.get('os_project_name') or
+ kwargs.get('os_tenant_name'))
ks_kwargs = {
'username': kwargs.get('os_username'),
'password': kwargs.get('os_password'),
- 'tenant_id': kwargs.get('os_tenant_id'),
- 'tenant_name': kwargs.get('os_tenant_name'),
+ 'user_id': kwargs.get('os_user_id'),
+ 'user_domain_id': kwargs.get('os_user_domain_id'),
+ 'user_domain_name': kwargs.get('os_user_domain_name'),
+ 'project_id': project_id,
+ 'project_name': project_name,
+ 'project_domain_name': kwargs.get('os_project_domain_name'),
+ 'project_domain_id': kwargs.get('os_project_domain_id'),
'auth_url': kwargs.get('os_auth_url'),
- 'region_name': kwargs.get('os_region_name'),
- 'service_type': kwargs.get('os_service_type'),
- 'endpoint_type': kwargs.get('os_endpoint_type'),
'cacert': kwargs.get('os_cacert'),
- 'insecure': kwargs.get('insecure'),
+ 'cert': kwargs.get('os_cert'),
+ 'key': kwargs.get('os_key'),
+ 'insecure': kwargs.get('insecure')
}
- _ksclient = _get_ksclient(**ks_kwargs)
- token = token or (lambda: _ksclient.auth_token)
+
+ # retrieve session
+ ks_session = _get_keystone_session(**ks_kwargs)
+ token = token or (lambda: ks_session.get_token())
endpoint = kwargs.get('ceilometer_url') or \
- _get_endpoint(_ksclient, **ks_kwargs)
+ _get_endpoint(ks_session, **ks_kwargs)
cli_kwargs = {
'token': token,
'insecure': kwargs.get('insecure'),
'timeout': kwargs.get('timeout'),
'cacert': kwargs.get('os_cacert'),
- 'cert_file': kwargs.get('cert_file'),
- 'key_file': kwargs.get('key_file'),
+ 'cert_file': kwargs.get('os_cert'),
+ 'key_file': kwargs.get('os_key')
}
return Client(api_version, endpoint, **cli_kwargs)
diff --git a/ceilometerclient/shell.py b/ceilometerclient/shell.py
index 6e26f31..46a460c 100644
--- a/ceilometerclient/shell.py
+++ b/ceilometerclient/shell.py
@@ -32,36 +32,11 @@ from ceilometerclient.openstack.common import strutils
class CeilometerShell(object):
- def get_base_parser(self):
- parser = argparse.ArgumentParser(
- prog='ceilometer',
- description=__doc__.strip(),
- epilog='See "ceilometer help COMMAND" '
- 'for help on a specific command.',
- add_help=False,
- formatter_class=HelpFormatter,
- )
-
- # Global arguments
- parser.add_argument('-h', '--help',
- action='store_true',
- help=argparse.SUPPRESS,
- )
-
- parser.add_argument('--version',
- action='version',
- version=ceilometerclient.__version__)
-
- parser.add_argument('-d', '--debug',
- default=bool(cliutils.env('CEILOMETERCLIENT_DEBUG')
- ),
- action='store_true',
- help='Defaults to env[CEILOMETERCLIENT_DEBUG].')
-
- parser.add_argument('-v', '--verbose',
- default=False, action="store_true",
- help="Print more verbose output.")
-
+ def _append_identity_args(self, parser):
+ # FIXME(fabgia): identity related parameters should be passed by the
+ # Keystone client itself to avoid constant update in all the services
+ # clients. When this fix is merged this method can be made obsolete.
+ # Bug: https://bugs.launchpad.net/python-keystoneclient/+bug/1332337
parser.add_argument('-k', '--insecure',
default=False,
action='store_true',
@@ -72,32 +47,7 @@ class CeilometerShell(object):
"authorities. This option should be used with "
"caution.")
- parser.add_argument('--cert-file',
- help='Path of certificate file to use in SSL '
- 'connection. This file can optionally be prepended'
- ' with the private key.')
-
- parser.add_argument('--key-file',
- help='Path of client key to use in SSL connection.'
- ' This option is not necessary if your key is '
- 'prepended to your cert file.')
-
- parser.add_argument('--os-cacert',
- metavar='<ca-certificate-file>',
- dest='os_cacert',
- default=cliutils.env('OS_CACERT'),
- help='Path of CA TLS certificate(s) used to verify'
- 'the remote server\'s certificate. Without this '
- 'option ceilometer looks for the default system '
- 'CA certificates.')
- parser.add_argument('--ca-file',
- dest='os_cacert',
- help='DEPRECATED! Use --os-cacert.')
-
- parser.add_argument('--timeout',
- default=600,
- help='Number of seconds to wait for a response.')
-
+ # User related options
parser.add_argument('--os-username',
default=cliutils.env('OS_USERNAME'),
help='Defaults to env[OS_USERNAME].')
@@ -105,6 +55,10 @@ class CeilometerShell(object):
parser.add_argument('--os_username',
help=argparse.SUPPRESS)
+ parser.add_argument('--os-user-id',
+ default=cliutils.env('OS_USER_ID'),
+ help='Defaults to env[OS_USER_ID].')
+
parser.add_argument('--os-password',
default=cliutils.env('OS_PASSWORD'),
help='Defaults to env[OS_PASSWORD].')
@@ -112,9 +66,43 @@ class CeilometerShell(object):
parser.add_argument('--os_password',
help=argparse.SUPPRESS)
+ # Domain related options
+ parser.add_argument('--os-user-domain-id',
+ default=cliutils.env('OS_USER_DOMAIN_ID'),
+ help='Defaults to env[OS_USER_DOMAIN_ID].')
+
+ parser.add_argument('--os-user-domain-name',
+ default=cliutils.env('OS_USER_DOMAIN_NAME'),
+ help='Defaults to env[OS_USER_DOMAIN_NAME].')
+
+ parser.add_argument('--os-project-domain-id',
+ default=cliutils.env('OS_PROJECT_DOMAIN_ID'),
+ help='Defaults to env[OS_PROJECT_DOMAIN_ID].')
+
+ parser.add_argument('--os-project-domain-name',
+ default=cliutils.env('OS_PROJECT_DOMAIN_NAME'),
+ help='Defaults to env[OS_PROJECT_DOMAIN_NAME].')
+
+ # Project V3 or Tenant V2 related options
+ parser.add_argument('--os-project-id',
+ default=cliutils.env('OS_PROJECT_ID'),
+ help='Another way to specify tenant ID. '
+ 'This option is mutually exclusive with '
+ ' --os-tenant-id. '
+ 'Defaults to env[OS_PROJECT_ID].')
+
+ parser.add_argument('--os-project-name',
+ default=cliutils.env('OS_PROJECT_NAME'),
+ help='Another way to specify tenant name. '
+ 'This option is mutually exclusive with '
+ ' --os-tenant-name. '
+ 'Defaults to env[OS_PROJECT_NAME].')
+
parser.add_argument('--os-tenant-id',
default=cliutils.env('OS_TENANT_ID'),
- help='Defaults to env[OS_TENANT_ID].')
+ help='This option is mutually exclusive with '
+ ' --os-project-id. '
+ 'Defaults to env[OS_PROJECT_ID].')
parser.add_argument('--os_tenant_id',
help=argparse.SUPPRESS)
@@ -126,6 +114,7 @@ class CeilometerShell(object):
parser.add_argument('--os_tenant_name',
help=argparse.SUPPRESS)
+ # Auth related options
parser.add_argument('--os-auth-url',
default=cliutils.env('OS_AUTH_URL'),
help='Defaults to env[OS_AUTH_URL].')
@@ -133,6 +122,47 @@ class CeilometerShell(object):
parser.add_argument('--os_auth_url',
help=argparse.SUPPRESS)
+ parser.add_argument('--os-auth-token',
+ default=cliutils.env('OS_AUTH_TOKEN'),
+ help='Defaults to env[OS_AUTH_TOKEN].')
+
+ parser.add_argument('--os_auth_token',
+ help=argparse.SUPPRESS)
+
+ parser.add_argument('--os-cacert',
+ metavar='<ca-certificate-file>',
+ dest='os_cacert',
+ default=cliutils.env('OS_CACERT'),
+ help='Path of CA TLS certificate(s) used to verify'
+ 'the remote server\'s certificate. Without this '
+ 'option ceilometer looks for the default system '
+ 'CA certificates.')
+
+ parser.add_argument('--os-cert',
+ help='Path of certificate file to use in SSL '
+ 'connection. This file can optionally be '
+ 'prepended with the private key.')
+
+ parser.add_argument('--os-key',
+ help='Path of client key to use in SSL '
+ 'connection. This option is not necessary '
+ 'if your key is prepended to your cert file.')
+
+ # Service Catalog related options
+ parser.add_argument('--os-service-type',
+ default=cliutils.env('OS_SERVICE_TYPE'),
+ help='Defaults to env[OS_SERVICE_TYPE].')
+
+ parser.add_argument('--os_service_type',
+ help=argparse.SUPPRESS)
+
+ parser.add_argument('--os-endpoint-type',
+ default=cliutils.env('OS_ENDPOINT_TYPE'),
+ help='Defaults to env[OS_ENDPOINT_TYPE].')
+
+ parser.add_argument('--os_endpoint_type',
+ help=argparse.SUPPRESS)
+
parser.add_argument('--os-region-name',
default=cliutils.env('OS_REGION_NAME'),
help='Defaults to env[OS_REGION_NAME].')
@@ -140,12 +170,52 @@ class CeilometerShell(object):
parser.add_argument('--os_region_name',
help=argparse.SUPPRESS)
- parser.add_argument('--os-auth-token',
- default=cliutils.env('OS_AUTH_TOKEN'),
- help='Defaults to env[OS_AUTH_TOKEN].')
+ # Deprecated options
+ parser.add_argument('--ca-file',
+ dest='os_cacert',
+ help='DEPRECATED! Use --os-cacert.')
- parser.add_argument('--os_auth_token',
- help=argparse.SUPPRESS)
+ parser.add_argument('--cert-file',
+ dest='os_cert',
+ help='DEPRECATED! Use --os-cert.')
+
+ parser.add_argument('--key-file',
+ dest='os_key',
+ help='DEPRECATED! Use --os-key.')
+
+ def get_base_parser(self):
+ parser = argparse.ArgumentParser(
+ prog='ceilometer',
+ description=__doc__.strip(),
+ epilog='See "ceilometer help COMMAND" '
+ 'for help on a specific command.',
+ add_help=False,
+ formatter_class=HelpFormatter,
+ )
+
+ # Global arguments
+ parser.add_argument('-h', '--help',
+ action='store_true',
+ help=argparse.SUPPRESS,
+ )
+
+ parser.add_argument('--version',
+ action='version',
+ version=ceilometerclient.__version__)
+
+ parser.add_argument('-d', '--debug',
+ default=bool(cliutils.env('CEILOMETERCLIENT_DEBUG')
+ ),
+ action='store_true',
+ help='Defaults to env[CEILOMETERCLIENT_DEBUG].')
+
+ parser.add_argument('-v', '--verbose',
+ default=False, action="store_true",
+ help="Print more verbose output.")
+
+ parser.add_argument('--timeout',
+ default=600,
+ help='Number of seconds to wait for a response.')
parser.add_argument('--ceilometer-url',
default=cliutils.env('CEILOMETER_URL'),
@@ -163,19 +233,9 @@ class CeilometerShell(object):
parser.add_argument('--ceilometer_api_version',
help=argparse.SUPPRESS)
- parser.add_argument('--os-service-type',
- default=cliutils.env('OS_SERVICE_TYPE'),
- help='Defaults to env[OS_SERVICE_TYPE].')
-
- parser.add_argument('--os_service_type',
- help=argparse.SUPPRESS)
-
- parser.add_argument('--os-endpoint-type',
- default=cliutils.env('OS_ENDPOINT_TYPE'),
- help='Defaults to env[OS_ENDPOINT_TYPE].')
-
- parser.add_argument('--os_endpoint_type',
- help=argparse.SUPPRESS)
+ # FIXME(fabgia): identity related parameters should be passed by the
+ # Keystone client itself.
+ self._append_identity_args(parser)
return parser
@@ -247,6 +307,14 @@ class CeilometerShell(object):
# Return parsed args
return api_version, subcommand_parser.parse_args(argv)
+ def no_project_and_domain_set(self, args):
+ if not (args.os_project_id or (args.os_project_name and
+ (args.os_user_domain_name or args.os_user_domain_id)) or
+ (args.os_tenant_id or args.os_tenant_name)):
+ return True
+ else:
+ return False
+
def main(self, argv):
parsed = self.parse_args(argv)
if parsed == 0:
@@ -272,10 +340,17 @@ class CeilometerShell(object):
"either --os-password or via "
"env[OS_PASSWORD]")
- 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 self.no_project_and_domain_set(args):
+ # steer users towards Keystone V3 API
+ raise exc.CommandError("You must provide a project_id via "
+ "either --os-project-id or via "
+ "env[OS_PROJECT_ID] and "
+ "a domain_name via either "
+ "--os-user-domain-name or via "
+ "env[OS_USER_DOMAIN_NAME] or "
+ "a domain_id via either "
+ "--os-user-domain-id or via "
+ "env[OS_USER_DOMAIN_ID]")
if not args.os_auth_url:
raise exc.CommandError("You must provide an auth url via "
diff --git a/ceilometerclient/tests/test_client.py b/ceilometerclient/tests/test_client.py
index de46c9a..14aaca6 100644
--- a/ceilometerclient/tests/test_client.py
+++ b/ceilometerclient/tests/test_client.py
@@ -20,7 +20,7 @@ from ceilometerclient.v2 import client as v2client
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:5000/',
'os_auth_token': '1234',
'ceilometer_url': 'http://no.where'}
diff --git a/ceilometerclient/tests/test_shell.py b/ceilometerclient/tests/test_shell.py
index be6e115..5f0ffba 100644
--- a/ceilometerclient/tests/test_shell.py
+++ b/ceilometerclient/tests/test_shell.py
@@ -14,7 +14,7 @@ import re
import sys
import fixtures
-from keystoneclient.v2_0 import client as ksclient
+from keystoneclient import session as ks_session
import mock
import six
from testtools import matchers
@@ -24,25 +24,31 @@ from ceilometerclient import shell as ceilometer_shell
from ceilometerclient.tests import utils
from ceilometerclient.v1 import client as v1client
-FAKE_ENV = {'OS_USERNAME': 'username',
- 'OS_PASSWORD': 'password',
- 'OS_TENANT_NAME': 'tenant_name',
- 'OS_AUTH_URL': 'http://no.where'}
+FAKE_V2_ENV = {'OS_USERNAME': 'username',
+ 'OS_PASSWORD': 'password',
+ 'OS_TENANT_NAME': 'tenant_name',
+ 'OS_AUTH_URL': 'http://localhost:5000/v2.0'}
+
+FAKE_V3_ENV = {'OS_USERNAME': 'username',
+ 'OS_PASSWORD': 'password',
+ 'OS_USER_DOMAIN_NAME': 'domain_name',
+ 'OS_PROJECT_ID': '1234567890',
+ 'OS_AUTH_URL': 'http://localhost:5000/v3'}
class ShellTest(utils.BaseTestCase):
re_options = re.DOTALL | re.MULTILINE
# Patch os.environ to avoid required auth info.
- def make_env(self, exclude=None):
- env = dict((k, v) for k, v in FAKE_ENV.items() if k != exclude)
+ def make_env(self, env_version, exclude=None):
+ env = dict((k, v) for k, v in env_version.items() if k != exclude)
self.useFixture(fixtures.MonkeyPatch('os.environ', env))
def setUp(self):
super(ShellTest, self).setUp()
@mock.patch('sys.stdout', new=six.StringIO())
- @mock.patch.object(ksclient, 'Client')
+ @mock.patch.object(ks_session, 'Session')
@mock.patch.object(v1client.http.HTTPClient, 'json_request')
@mock.patch.object(v1client.http.HTTPClient, 'raw_request')
def shell(self, argstr, mock_ksclient, mock_json, mock_raw):
@@ -85,28 +91,60 @@ class ShellTest(utils.BaseTestCase):
self.assertThat(help_text,
matchers.MatchesRegex(r, self.re_options))
+
+class ShellKeystoneV2Test(ShellTest):
+
+ def test_auth_param(self):
+ self.make_env(FAKE_V2_ENV, exclude='OS_USERNAME')
+ self.test_help()
+
+ @mock.patch.object(ks_session, 'Session')
+ def test_debug_switch_raises_error(self, mock_ksclient):
+ mock_ksclient.side_effect = exc.HTTPUnauthorized
+ self.make_env(FAKE_V2_ENV)
+ args = ['--debug', 'event-list']
+ self.assertRaises(exc.HTTPUnauthorized, ceilometer_shell.main, args)
+
+ @mock.patch.object(ks_session, 'Session')
+ def test_dash_d_switch_raises_error(self, mock_ksclient):
+ mock_ksclient.side_effect = exc.CommandError("FAIL")
+ self.make_env(FAKE_V2_ENV)
+ args = ['-d', 'event-list']
+ self.assertRaises(exc.CommandError, ceilometer_shell.main, args)
+
+ @mock.patch('sys.stderr')
+ @mock.patch.object(ks_session, 'Session')
+ def test_no_debug_switch_no_raises_errors(self, mock_ksclient, __):
+ mock_ksclient.side_effect = exc.HTTPUnauthorized("FAIL")
+ self.make_env(FAKE_V2_ENV)
+ args = ['event-list']
+ self.assertRaises(SystemExit, ceilometer_shell.main, args)
+
+
+class ShellKeystoneV3Test(ShellTest):
+
def test_auth_param(self):
- self.make_env(exclude='OS_USERNAME')
+ self.make_env(FAKE_V3_ENV, exclude='OS_USER_DOMAIN_NAME')
self.test_help()
- @mock.patch.object(ksclient, 'Client')
+ @mock.patch.object(ks_session, 'Session')
def test_debug_switch_raises_error(self, mock_ksclient):
mock_ksclient.side_effect = exc.HTTPUnauthorized
- self.make_env()
+ self.make_env(FAKE_V3_ENV)
args = ['--debug', 'event-list']
self.assertRaises(exc.HTTPUnauthorized, ceilometer_shell.main, args)
- @mock.patch.object(ksclient, 'Client')
+ @mock.patch.object(ks_session, 'Session')
def test_dash_d_switch_raises_error(self, mock_ksclient):
mock_ksclient.side_effect = exc.CommandError("FAIL")
- self.make_env()
+ self.make_env(FAKE_V3_ENV)
args = ['-d', 'event-list']
self.assertRaises(exc.CommandError, ceilometer_shell.main, args)
@mock.patch('sys.stderr')
- @mock.patch.object(ksclient, 'Client')
+ @mock.patch.object(ks_session, 'Session')
def test_no_debug_switch_no_raises_errors(self, mock_ksclient, __):
mock_ksclient.side_effect = exc.HTTPUnauthorized("FAIL")
- self.make_env()
+ self.make_env(FAKE_V3_ENV)
args = ['event-list']
self.assertRaises(SystemExit, ceilometer_shell.main, args)