diff --git a/nova/compute/rpcapi.py b/nova/compute/rpcapi.py index ee270cd156db..96a65dadcbed 100644 --- a/nova/compute/rpcapi.py +++ b/nova/compute/rpcapi.py @@ -18,6 +18,7 @@ Client side of the compute RPC API. from oslo_log import log as logging import oslo_messaging as messaging from oslo_serialization import jsonutils +from oslo_utils import excutils import nova.conf from nova import context @@ -393,8 +394,22 @@ class ComputeAPI(object): # NOTE(danms): If we have a connection to the api database, # we should iterate all cells. If not, we must only look locally. if CONF.api_database.connection: - service_version = service_obj.get_minimum_version_all_cells( - context.get_admin_context(), ['nova-compute']) + try: + service_version = service_obj.get_minimum_version_all_cells( + context.get_admin_context(), ['nova-compute']) + except exception.DBNotAllowed: + # This most likely means we are in a nova-compute service + # configured with [upgrade_levels]/compute=auto and a + # connection to the API database. We should not be attempting + # to "get out" of our cell to look at the minimum versions of + # nova-compute services in other cells, so DBNotAllowed was + # raised. Log a user-friendly message and re-raise the error. + with excutils.save_and_reraise_exception(): + LOG.error('This service is configured for access to the ' + 'API database but is not allowed to directly ' + 'access the database. You should run this ' + 'service without the [api_database]/connection ' + 'config option.') else: service_version = objects.Service.get_minimum_version( context.get_admin_context(), 'nova-compute') diff --git a/nova/conf/database.py b/nova/conf/database.py index 9355becc8e72..c85689f89656 100644 --- a/nova/conf/database.py +++ b/nova/conf/database.py @@ -36,13 +36,16 @@ api_db_group = cfg.OptGroup('api_database', The *Nova API Database* is a separate database which is used for information which is used across *cells*. This database is mandatory since the Mitaka release (13.0.0). + +This group should **not** be configured for the ``nova-compute`` service. """) api_db_opts = [ # TODO(markus_z): This should probably have a required=True attribute cfg.StrOpt('connection', secret=True, - help=''), + # This help gets appended to the oslo.db help so prefix with a space. + help=' Do not set this for the ``nova-compute`` service.'), cfg.StrOpt('connection_parameters', default='', help=''), diff --git a/nova/tests/unit/compute/test_rpcapi.py b/nova/tests/unit/compute/test_rpcapi.py index a96b9dcf4797..85f0d93d88fb 100644 --- a/nova/tests/unit/compute/test_rpcapi.py +++ b/nova/tests/unit/compute/test_rpcapi.py @@ -614,3 +614,29 @@ class ComputeRpcAPITestCase(test.NoDBTestCase): compute_rpcapi.ComputeAPI() mock_allcells.assert_called_once_with(mock.ANY, ['nova-compute']) mock_minver.assert_not_called() + + @mock.patch('nova.compute.rpcapi.LOG.error') + @mock.patch('nova.objects.Service.get_minimum_version') + @mock.patch('nova.objects.service.get_minimum_version_all_cells', + side_effect=exception.DBNotAllowed(binary='nova-compute')) + def test_version_cap_all_cells_no_access(self, mock_allcells, mock_minver, + mock_log_error): + """Tests a scenario where nova-compute is configured with a connection + to the API database and fails trying to get the minium nova-compute + service version across all cells because nova-compute is configured to + not allow direct database access. + """ + self.flags(connection='sqlite:///', group='api_database') + compute_rpcapi.LAST_VERSION = None + self.assertRaises(exception.DBNotAllowed, + compute_rpcapi.ComputeAPI()._determine_version_cap, + mock.Mock()) + mock_allcells.assert_called_once_with(mock.ANY, ['nova-compute']) + mock_minver.assert_not_called() + # Make sure the expected error was logged. + mock_log_error.assert_called_once_with( + 'This service is configured for access to the ' + 'API database but is not allowed to directly ' + 'access the database. You should run this ' + 'service without the [api_database]/connection ' + 'config option.')