Don't fail if a provider driver cannot be loaded in Octavia API
Fix an issue that prevents the Octavia API service to be correctly initialized when it fails to load a provider driver. When enabled_provider_drivers setting is not correctly configured (ex: if it contains a non existing driver) or when a provider driver fails to load, the exception was not caught by the Octavia API service, so the service was not properly configured and the whole Octavia API was unreachable. Now the Octavia API service skips the driver initialization in case of errors, removes the driver(s) from the enabled list, and the other provider drivers are functional. Story 2008710 Task 42044 Depends-on: https://review.opendev.org/c/openstack/octavia/+/964892 Change-Id: I34341e1aaad1524e3e0834309c5f6897f176af53 Signed-off-by: Zachary Raines <zachary.raines@canonical.com>
This commit is contained in:
committed by
Zachary Raines
parent
ffd4fa757f
commit
6fc1abb780
@@ -44,8 +44,20 @@ def get_pecan_config():
|
||||
|
||||
def _init_drivers():
|
||||
"""Initialize provider drivers."""
|
||||
for provider in CONF.api_settings.enabled_provider_drivers:
|
||||
driver_factory.get_driver(provider)
|
||||
providers_to_remove = []
|
||||
enabled_providers = driver_factory.get_providers()
|
||||
for provider in enabled_providers:
|
||||
try:
|
||||
driver_factory.get_driver(provider)
|
||||
except Exception:
|
||||
LOG.exception("Cannot load driver '%s', will remove from "
|
||||
"service. Please check "
|
||||
"[api_settings]/enabled_provider_drivers in "
|
||||
"octavia.conf for correctness.", provider)
|
||||
providers_to_remove.append(provider)
|
||||
|
||||
if providers_to_remove:
|
||||
driver_factory.remove_providers(providers_to_remove)
|
||||
|
||||
|
||||
def setup_app(pecan_config=None, debug=False, argv=None):
|
||||
|
||||
@@ -48,3 +48,14 @@ def get_driver(provider):
|
||||
provider, str(e))
|
||||
raise exceptions.ProviderNotFound(prov=provider)
|
||||
return driver
|
||||
|
||||
|
||||
def remove_providers(providers):
|
||||
# Presumably these provider drivers failed to load, remove so they do not
|
||||
# show up in the available list
|
||||
for provider in providers:
|
||||
CONF.api_settings.enabled_provider_drivers.pop(provider)
|
||||
|
||||
|
||||
def get_providers():
|
||||
return CONF.api_settings.enabled_provider_drivers
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
# under the License.
|
||||
|
||||
from octavia_lib.api.drivers import exceptions as lib_exceptions
|
||||
from oslo_config import cfg
|
||||
from oslo_log import log as logging
|
||||
from pecan import expose as pecan_expose
|
||||
from pecan import request as pecan_request
|
||||
@@ -26,7 +25,6 @@ from octavia.api.v2.types import provider as provider_types
|
||||
from octavia.common import constants
|
||||
from octavia.common import exceptions
|
||||
|
||||
CONF = cfg.CONF
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@@ -46,7 +44,7 @@ class ProviderController(base.BaseController):
|
||||
self._auth_validate_action(context, context.project_id,
|
||||
constants.RBAC_GET_ALL)
|
||||
|
||||
enabled_providers = CONF.api_settings.enabled_provider_drivers
|
||||
enabled_providers = driver_factory.get_providers()
|
||||
response_list = [
|
||||
provider_types.ProviderResponse(name=key, description=value) for
|
||||
key, value in enabled_providers.items()]
|
||||
|
||||
54
octavia/tests/unit/api/test_app.py
Normal file
54
octavia/tests/unit/api/test_app.py
Normal file
@@ -0,0 +1,54 @@
|
||||
# Copyright 2021 Red Hat, Inc. 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.
|
||||
|
||||
from unittest import mock
|
||||
|
||||
from oslo_config import cfg
|
||||
from oslo_config import fixture as oslo_fixture
|
||||
|
||||
from octavia.api import app
|
||||
from octavia.api.drivers import driver_factory
|
||||
import octavia.tests.unit.base as base
|
||||
|
||||
|
||||
class TestApp(base.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
|
||||
@mock.patch.object(driver_factory, "get_driver")
|
||||
def test__init_drivers(self, mock_get_driver):
|
||||
self.CONF = self.useFixture(oslo_fixture.Config(cfg.CONF))
|
||||
self.CONF.config(
|
||||
group="api_settings",
|
||||
enabled_provider_drivers="provider1:desc1,provider2:desc2")
|
||||
|
||||
app._init_drivers()
|
||||
mock_get_driver.assert_any_call("provider1")
|
||||
mock_get_driver.assert_any_call("provider2")
|
||||
|
||||
@mock.patch.object(driver_factory, "get_driver")
|
||||
def test__init_drivers_with_error(self, mock_get_driver):
|
||||
self.CONF = self.useFixture(oslo_fixture.Config(cfg.CONF))
|
||||
self.CONF.config(
|
||||
group="api_settings",
|
||||
enabled_provider_drivers="provider1:desc1,provider2:desc2")
|
||||
|
||||
mock_get_driver.side_effect = [True, Exception('Internal Error')]
|
||||
|
||||
app._init_drivers()
|
||||
mock_get_driver.assert_any_call("provider1")
|
||||
mock_get_driver.assert_any_call("provider2")
|
||||
enabled_providers = driver_factory.get_providers()
|
||||
self.assertEqual(enabled_providers, {'provider1': 'desc1'})
|
||||
@@ -0,0 +1,6 @@
|
||||
---
|
||||
fixes:
|
||||
- |
|
||||
Fix an issue that prevents the Octavia API service to be correctly
|
||||
initialized when it fails to load a provider driver. It will now
|
||||
fail gracefully and remove the driver from the enabled list.
|
||||
Reference in New Issue
Block a user