Fail if required extensions are missing
If the required extensions are missing, we currently log an error that is going to be practically ignored. That said, the unfulfilled requirement will most definitely going to lead to other failures, so we might as well fail fast. This patch also cleans up some <barf>dns-integration nonsense</barf> within the ML2 framework: the extension must not be declared statically as it's being loaded by the extension manager, and this fixes the lousy unit tests we have to live with. As for the db base plugin, some cleanup is still overdue, but it will have to be taken care of in a follow-up patch. Closes-bug: #1538623 Change-Id: Id50eeb52c5d209170042b48821a29af3421c2f5c
This commit is contained in:
parent
5ccfbb5b25
commit
b14c06b5ed
@ -74,6 +74,11 @@ Document common pitfalls as well as good practices done during plugin developmen
|
|||||||
* When adding behavior to the L2 and L3 db base classes, do not assume that
|
* When adding behavior to the L2 and L3 db base classes, do not assume that
|
||||||
there is an agent on the other side of the message broker that interacts
|
there is an agent on the other side of the message broker that interacts
|
||||||
with the server. Plugins may not rely on `agents <https://review.openstack.org/#/c/174020/>`_ at all.
|
with the server. Plugins may not rely on `agents <https://review.openstack.org/#/c/174020/>`_ at all.
|
||||||
|
* Be mindful of required capabilities when you develop plugin extensions. The
|
||||||
|
`Extension description <https://github.com/openstack/neutron/blob/master/neutron/api/extensions.py#L122>`_ provides the ability to specify the list of required capabilities
|
||||||
|
for the extension you are developing. By declaring this list, the server will
|
||||||
|
not start up if the requirements are not met, thus avoiding leading the system
|
||||||
|
to experience undetermined behavior at runtime.
|
||||||
|
|
||||||
Database interaction
|
Database interaction
|
||||||
~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~
|
||||||
|
@ -440,10 +440,11 @@ class ExtensionManager(object):
|
|||||||
# Exit loop as no progress was made
|
# Exit loop as no progress was made
|
||||||
break
|
break
|
||||||
if exts_to_process:
|
if exts_to_process:
|
||||||
# NOTE(salv-orlando): Consider whether this error should be fatal
|
|
||||||
LOG.error(_LE("It was impossible to process the following "
|
LOG.error(_LE("It was impossible to process the following "
|
||||||
"extensions: %s because of missing requirements."),
|
"extensions: %s because of missing requirements."),
|
||||||
','.join(exts_to_process.keys()))
|
','.join(exts_to_process.keys()))
|
||||||
|
raise exceptions.ExtensionsNotFound(
|
||||||
|
extensions=list(exts_to_process.keys()))
|
||||||
|
|
||||||
# Extending extensions' attributes map.
|
# Extending extensions' attributes map.
|
||||||
for ext in processed_exts.values():
|
for ext in processed_exts.values():
|
||||||
|
@ -1172,7 +1172,8 @@ class NeutronDbPluginV2(db_base_plugin_common.DbBasePluginCommon,
|
|||||||
status=p.get('status', constants.PORT_STATUS_ACTIVE),
|
status=p.get('status', constants.PORT_STATUS_ACTIVE),
|
||||||
device_id=p['device_id'],
|
device_id=p['device_id'],
|
||||||
device_owner=p['device_owner'])
|
device_owner=p['device_owner'])
|
||||||
if 'dns_name' in p:
|
if ('dns-integration' in self.supported_extension_aliases and
|
||||||
|
'dns_name' in p):
|
||||||
request_dns_name = self._get_request_dns_name(p)
|
request_dns_name = self._get_request_dns_name(p)
|
||||||
port_data['dns_name'] = request_dns_name
|
port_data['dns_name'] = request_dns_name
|
||||||
|
|
||||||
@ -1190,13 +1191,15 @@ class NeutronDbPluginV2(db_base_plugin_common.DbBasePluginCommon,
|
|||||||
|
|
||||||
ips = self.ipam.allocate_ips_for_port_and_store(context, port,
|
ips = self.ipam.allocate_ips_for_port_and_store(context, port,
|
||||||
port_id)
|
port_id)
|
||||||
if 'dns_name' in p:
|
if ('dns-integration' in self.supported_extension_aliases and
|
||||||
|
'dns_name' in p):
|
||||||
dns_assignment = []
|
dns_assignment = []
|
||||||
if ips:
|
if ips:
|
||||||
dns_assignment = self._get_dns_names_for_port(
|
dns_assignment = self._get_dns_names_for_port(
|
||||||
context, ips, request_dns_name)
|
context, ips, request_dns_name)
|
||||||
|
|
||||||
if 'dns_name' in p:
|
if ('dns-integration' in self.supported_extension_aliases and
|
||||||
|
'dns_name' in p):
|
||||||
db_port['dns_assignment'] = dns_assignment
|
db_port['dns_assignment'] = dns_assignment
|
||||||
return self._make_port_dict(db_port, process_extensions=False)
|
return self._make_port_dict(db_port, process_extensions=False)
|
||||||
|
|
||||||
|
@ -125,7 +125,7 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2,
|
|||||||
"multi-provider", "allowed-address-pairs",
|
"multi-provider", "allowed-address-pairs",
|
||||||
"extra_dhcp_opt", "subnet_allocation",
|
"extra_dhcp_opt", "subnet_allocation",
|
||||||
"net-mtu", "vlan-transparent",
|
"net-mtu", "vlan-transparent",
|
||||||
"address-scope", "dns-integration",
|
"address-scope",
|
||||||
"availability_zone",
|
"availability_zone",
|
||||||
"network_availability_zone"]
|
"network_availability_zone"]
|
||||||
|
|
||||||
|
@ -502,6 +502,13 @@ class RequestExtensionTest(base.BaseTestCase):
|
|||||||
|
|
||||||
class ExtensionManagerTest(base.BaseTestCase):
|
class ExtensionManagerTest(base.BaseTestCase):
|
||||||
|
|
||||||
|
def test_missing_required_extensions(self):
|
||||||
|
ext_mgr = extensions.ExtensionManager('')
|
||||||
|
attr_map = {}
|
||||||
|
ext_mgr.add_extension(ext_stubs.StubExtensionWithReqs('foo_alias'))
|
||||||
|
self.assertRaises(exceptions.ExtensionsNotFound,
|
||||||
|
ext_mgr.extend_resources, "2.0", attr_map)
|
||||||
|
|
||||||
def test_invalid_extensions_are_not_registered(self):
|
def test_invalid_extensions_are_not_registered(self):
|
||||||
|
|
||||||
class InvalidExtension(object):
|
class InvalidExtension(object):
|
||||||
|
@ -1400,8 +1400,7 @@ class OvsAgentSchedulerTestCase(OvsAgentSchedulerTestCaseBase):
|
|||||||
exc.HTTPNotFound.code)
|
exc.HTTPNotFound.code)
|
||||||
|
|
||||||
|
|
||||||
class OvsDhcpAgentNotifierTestCase(test_l3.L3NatTestCaseMixin,
|
class OvsDhcpAgentNotifierTestCase(test_agent.AgentDBTestMixIn,
|
||||||
test_agent.AgentDBTestMixIn,
|
|
||||||
AgentSchedulerTestMixIn,
|
AgentSchedulerTestMixIn,
|
||||||
test_plugin.NeutronDbPluginV2TestCase):
|
test_plugin.NeutronDbPluginV2TestCase):
|
||||||
plugin_str = 'neutron.plugins.ml2.plugin.Ml2Plugin'
|
plugin_str = 'neutron.plugins.ml2.plugin.Ml2Plugin'
|
||||||
|
@ -37,6 +37,12 @@ class StubExtension(extensions.ExtensionDescriptor):
|
|||||||
return ""
|
return ""
|
||||||
|
|
||||||
|
|
||||||
|
class StubExtensionWithReqs(StubExtension):
|
||||||
|
|
||||||
|
def get_required_extensions(self):
|
||||||
|
return ["foo"]
|
||||||
|
|
||||||
|
|
||||||
class StubPlugin(object):
|
class StubPlugin(object):
|
||||||
|
|
||||||
def __init__(self, supported_extensions=None):
|
def __init__(self, supported_extensions=None):
|
||||||
|
@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
fixes:
|
||||||
|
- The server will fail to start if any of the declared required
|
||||||
|
extensions, as needed by core and service plugins, are not
|
||||||
|
properly configured.
|
Loading…
Reference in New Issue
Block a user