From 00310442a2b3ed25f5a78737f072794cb7b23fdd Mon Sep 17 00:00:00 2001 From: Pierre Padrixe Date: Fri, 24 Jan 2014 18:32:01 +0100 Subject: [PATCH] Add deployment check subcommand * Check keystone endpoints and print user-friendly messages so the user can easily troubleshoot issues, * List all available services of your deployed OpenStack, * Refactoring of benchmark.engine.bind in order to avoid redundancy. Implements blueprint deployment-check-subcommand Change-Id: Iecfc2e4c093f567b56c3990c598326942c50e34a --- rally/benchmark/engine.py | 15 +-------------- rally/cmd/main.py | 30 ++++++++++++++++++++++++++++++ rally/osclients.py | 22 ++++++++++++++++++++++ tests/benchmark/test_engine.py | 30 ------------------------------ tests/fakes.py | 3 +++ tests/test_osclients.py | 25 +++++++++++++++++++++++++ 6 files changed, 81 insertions(+), 44 deletions(-) diff --git a/rally/benchmark/engine.py b/rally/benchmark/engine.py index a1f395b920..407898d900 100644 --- a/rally/benchmark/engine.py +++ b/rally/benchmark/engine.py @@ -16,8 +16,6 @@ import json import jsonschema -from keystoneclient import exceptions as keystone_exceptions - from rally.benchmark import base from rally.benchmark import runner from rally import consts @@ -161,18 +159,7 @@ class TestEngine(object): password=self.endpoint['password'], tenant_name=self.endpoint['tenant_name'], auth_url=self.endpoint['auth_url']) - - try: - # Ensure that user is admin - roles = clients.get_keystone_client().auth_ref['user']['roles'] - if not any("admin" == role['name'] for role in roles): - raise exceptions.InvalidAdminException( - username=self.endpoint["username"]) - except keystone_exceptions.Unauthorized: - raise exceptions.InvalidEndpointsException() - except keystone_exceptions.AuthorizationFailure: - raise exceptions.HostUnreachableException( - url=self.endpoint['auth_url']) + clients.get_verified_keystone_client() return self def __enter__(self): diff --git a/rally/cmd/main.py b/rally/cmd/main.py index 843b7d3e06..b24d1b385b 100644 --- a/rally/cmd/main.py +++ b/rally/cmd/main.py @@ -31,6 +31,7 @@ from rally import exceptions from rally import fileutils from rally.openstack.common.gettextutils import _ from rally.orchestrator import api +from rally import osclients from rally import processing @@ -145,6 +146,35 @@ class DeploymentCommands(object): table.add_row([endpoint.get(m, '') for m in headers]) print(table) + @cliutils.args('--deploy-id', dest='deploy_id', type=str, required=False, + help='UUID of a deployment.') + def check(self, deploy_id=None): + """Check the deployment. + + Check keystone authentication and list all available services. + + :param deploy_id: a UUID of the deployment + """ + deploy_id = deploy_id or envutils.default_deployment_id() + headers = ['services', 'type', 'status'] + table = prettytable.PrettyTable(headers) + try: + endpoint = db.deployment_get(deploy_id)['endpoint'] + clients = osclients.Clients(username=endpoint['username'], + password=endpoint['password'], + tenant_name=endpoint['tenant_name'], + auth_url=endpoint['auth_url']) + client = clients.get_verified_keystone_client() + print("keystone endpoints are valid and following services are " + "available:") + for service in client.service_catalog.get_data(): + table.add_row([service['name'], service['type'], 'Available']) + except exceptions.InvalidArgumentsException: + table.add_row(['keystone', 'identity', 'Error']) + print(_("Authentication Issues: %s.") + % sys.exc_info()[1]) + print(table) + class TaskCommands(object): diff --git a/rally/osclients.py b/rally/osclients.py index 8ed20d5e84..14882049ee 100644 --- a/rally/osclients.py +++ b/rally/osclients.py @@ -17,9 +17,12 @@ import urlparse from cinderclient import client as cinder import glanceclient as glance +from keystoneclient import exceptions as keystone_exceptions from keystoneclient.v2_0 import client as keystone from novaclient import client as nova +from rally import exceptions + class Clients(object): """This class simplify and unify work with openstack python clients.""" @@ -42,6 +45,25 @@ class Clients(object): self.cache["keystone"] = client return client + def get_verified_keystone_client(self): + """Ensure keystone endpoints are valid and then authenticate + + :returns: Keystone Client + """ + try: + # Ensure that user is admin + client = self.get_keystone_client() + roles = client.auth_ref['user']['roles'] + if not any('admin' == role['name'] for role in roles): + raise exceptions.InvalidAdminException( + username=self.kw['username']) + except keystone_exceptions.Unauthorized: + raise exceptions.InvalidEndpointsException() + except keystone_exceptions.AuthorizationFailure: + raise exceptions.HostUnreachableException( + url=self.kw['auth_url']) + return client + def get_nova_client(self, version='2'): """Returns nova client.""" if "nova" in self.cache: diff --git a/tests/benchmark/test_engine.py b/tests/benchmark/test_engine.py index aee0f798ed..f66313a400 100644 --- a/tests/benchmark/test_engine.py +++ b/tests/benchmark/test_engine.py @@ -17,8 +17,6 @@ import mock -from keystoneclient import exceptions as keystone_exceptions - from rally.benchmark import engine from rally import consts from rally import exceptions @@ -122,34 +120,6 @@ class TestEngineTestCase(test.TestCase): with tester.bind(self.valid_endpoint): self.assertEqual(tester.endpoint, self.valid_endpoint) - @mock.patch("rally.benchmark.engine.osclients") - def test_bind_user_not_admin(self, mock_osclients): - mock_osclients.Clients.return_value = fakes.FakeClients() - mock_osclients.Clients.return_value.get_keystone_client(). \ - auth_ref['user']['roles'] = [{'name': 'notadmin'}] - tester = engine.TestEngine(self.valid_test_config_continuous_times, - mock.MagicMock()) - self.assertRaises(exceptions.InvalidAdminException, - tester.bind, self.valid_endpoint) - - @mock.patch("rally.cmd.main.api.engine.osclients.Clients" - ".get_keystone_client") - def test_bind_unauthorized_keystone(self, mock_osclients): - mock_osclients.side_effect = keystone_exceptions.Unauthorized - tester = engine.TestEngine(self.valid_test_config_continuous_times, - mock.MagicMock()) - self.assertRaises(exceptions.InvalidEndpointsException, - tester.bind, self.valid_endpoint) - - @mock.patch("rally.cmd.main.api.engine.osclients.Clients" - ".get_keystone_client") - def test_bind_keystone_host_unreachable(self, mock_osclients): - mock_osclients.side_effect = keystone_exceptions.AuthorizationFailure - tester = engine.TestEngine(self.valid_test_config_continuous_times, - mock.MagicMock()) - self.assertRaises(exceptions.HostUnreachableException, - tester.bind, self.valid_endpoint) - @mock.patch("rally.benchmark.runner.ScenarioRunner.run") @mock.patch("rally.benchmark.utils.osclients") @mock.patch("rally.benchmark.engine.osclients") diff --git a/tests/fakes.py b/tests/fakes.py index 63aec485d7..62fd2336d9 100644 --- a/tests/fakes.py +++ b/tests/fakes.py @@ -374,6 +374,9 @@ class FakeClients(object): self.keystone = FakeKeystoneClient() return self.keystone + def get_verified_keystone_client(self): + return self.get_keystone_client() + def get_nova_client(self): if self.nova is not None: return self.nova diff --git a/tests/test_osclients.py b/tests/test_osclients.py index cc05b8d11f..1287c41cae 100644 --- a/tests/test_osclients.py +++ b/tests/test_osclients.py @@ -15,6 +15,9 @@ import mock +from keystoneclient import exceptions as keystone_exceptions + +from rally import exceptions from rally import osclients from tests import fakes from tests import test @@ -47,6 +50,28 @@ class OSClientsTestCase(test.TestCase): mock_keystone.Client.assert_called_once_with(**kwargs) self.assertEqual(self.clients.cache["keystone"], fake_keystone) + @mock.patch('rally.osclients.Clients.get_keystone_client') + def test_get_verified_keystone_client_user_not_admin(self, mock_keystone): + mock_keystone.return_value = fakes.FakeKeystoneClient() + mock_keystone.return_value.auth_ref['user']['roles'] = \ + [{'name': 'notadmin'}] + self.assertRaises(exceptions.InvalidAdminException, + self.clients.get_verified_keystone_client) + + @mock.patch('rally.osclients.Clients.get_keystone_client') + def test_get_verified_keystone_client_unauthorized(self, mock_keystone): + mock_keystone.return_value = fakes.FakeKeystoneClient() + mock_keystone.side_effect = keystone_exceptions.Unauthorized + self.assertRaises(exceptions.InvalidEndpointsException, + self.clients.get_verified_keystone_client) + + @mock.patch('rally.osclients.Clients.get_keystone_client') + def test_get_verified_keystone_client_unreachable(self, mock_keystone): + mock_keystone.return_value = fakes.FakeKeystoneClient() + mock_keystone.side_effect = keystone_exceptions.AuthorizationFailure + self.assertRaises(exceptions.HostUnreachableException, + self.clients.get_verified_keystone_client) + def test_get_nova_client(self): with mock.patch('rally.osclients.nova') as mock_nova: fake_nova = fakes.FakeNovaClient()