subnet calls of ml2 mechanism driver
Implements blueprint ml2-mechanism-driver-subnet-calls Change-Id: Ib9a8009975959692f46f80fb2a850fcc2b22debe
This commit is contained in:
parent
19c29cd27c
commit
49aaf280e1
@ -164,6 +164,38 @@ class NetworkContext(object):
|
||||
pass
|
||||
|
||||
|
||||
class SubnetContext(object):
|
||||
"""Context passed to MechanismDrivers for changes to subnet resources.
|
||||
|
||||
A SubnetContext instance wraps a subnet resource. It provides
|
||||
helper methods for accessing other relevant information. Results
|
||||
from expensive operations are cached so that other
|
||||
MechanismDrivers can freely access the same information.
|
||||
"""
|
||||
|
||||
__metaclass__ = ABCMeta
|
||||
|
||||
@abstractproperty
|
||||
def current(self):
|
||||
"""Return the current state of the subnet.
|
||||
|
||||
Return the current state of the subnet, as defined by
|
||||
NeutronPluginBaseV2.create_subnet and all extensions in the
|
||||
ml2 plugin.
|
||||
"""
|
||||
pass
|
||||
|
||||
@abstractproperty
|
||||
def original(self):
|
||||
"""Return the original state of the subnet.
|
||||
|
||||
Return the original state of the subnet, prior to a call to
|
||||
update_subnet. Method is only valid within calls to
|
||||
update_subnet_precommit and update_subnet_postcommit.
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
class PortContext(object):
|
||||
"""Context passed to MechanismDrivers for changes to port resources.
|
||||
|
||||
@ -222,8 +254,6 @@ class MechanismDriver(object):
|
||||
methods that are part of the database transaction.
|
||||
"""
|
||||
|
||||
# TODO(apech): add calls for subnets
|
||||
|
||||
__metaclass__ = ABCMeta
|
||||
|
||||
@abstractmethod
|
||||
@ -326,6 +356,96 @@ class MechanismDriver(object):
|
||||
"""
|
||||
pass
|
||||
|
||||
def create_subnet_precommit(self, context):
|
||||
"""Allocate resources for a new subnet.
|
||||
|
||||
:param context: SubnetContext instance describing the new
|
||||
subnet.
|
||||
|
||||
Create a new subnet, allocating resources as necessary in the
|
||||
database. Called inside transaction context on session. Call
|
||||
cannot block. Raising an exception will result in a rollback
|
||||
of the current transaction.
|
||||
"""
|
||||
pass
|
||||
|
||||
def create_subnet_postcommit(self, context):
|
||||
"""Create a subnet.
|
||||
|
||||
:param context: SubnetContext instance describing the new
|
||||
subnet.
|
||||
|
||||
Called after the transaction commits. Call can block, though
|
||||
will block the entire process so care should be taken to not
|
||||
drastically affect performance. Raising an exception will
|
||||
cause the deletion of the resource.
|
||||
"""
|
||||
pass
|
||||
|
||||
def update_subnet_precommit(self, context):
|
||||
"""Update resources of a subnet.
|
||||
|
||||
:param context: SubnetContext instance describing the new
|
||||
state of the subnet, as well as the original state prior
|
||||
to the update_subnet call.
|
||||
|
||||
Update values of a subnet, updating the associated resources
|
||||
in the database. Called inside transaction context on session.
|
||||
Raising an exception will result in rollback of the
|
||||
transaction.
|
||||
|
||||
update_subnet_precommit is called for all changes to the
|
||||
subnet state. It is up to the mechanism driver to ignore
|
||||
state or state changes that it does not know or care about.
|
||||
"""
|
||||
pass
|
||||
|
||||
def update_subnet_postcommit(self, context):
|
||||
"""Update a subnet.
|
||||
|
||||
:param context: SubnetContext instance describing the new
|
||||
state of the subnet, as well as the original state prior
|
||||
to the update_subnet call.
|
||||
|
||||
Called after the transaction commits. Call can block, though
|
||||
will block the entire process so care should be taken to not
|
||||
drastically affect performance. Raising an exception will
|
||||
cause the deletion of the resource.
|
||||
|
||||
update_subnet_postcommit is called for all changes to the
|
||||
subnet state. It is up to the mechanism driver to ignore
|
||||
state or state changes that it does not know or care about.
|
||||
"""
|
||||
pass
|
||||
|
||||
def delete_subnet_precommit(self, context):
|
||||
"""Delete resources for a subnet.
|
||||
|
||||
:param context: SubnetContext instance describing the current
|
||||
state of the subnet, prior to the call to delete it.
|
||||
|
||||
Delete subnet resources previously allocated by this
|
||||
mechanism driver for a subnet. Called inside transaction
|
||||
context on session. Runtime errors are not expected, but
|
||||
raising an exception will result in rollback of the
|
||||
transaction.
|
||||
"""
|
||||
pass
|
||||
|
||||
def delete_subnet_postcommit(self, context):
|
||||
"""Delete a subnet.
|
||||
|
||||
:param context: SubnetContext instance describing the current
|
||||
state of the subnet, prior to the call to delete it.
|
||||
|
||||
Called after the transaction commits. Call can block, though
|
||||
will block the entire process so care should be taken to not
|
||||
drastically affect performance. Runtime errors are not
|
||||
expected, and will not prevent the resource from being
|
||||
deleted.
|
||||
"""
|
||||
pass
|
||||
|
||||
def create_port_precommit(self, context):
|
||||
"""Allocate resources for a new port.
|
||||
|
||||
|
@ -35,12 +35,15 @@ class NetworkContext(MechanismDriverContext, api.NetworkContext):
|
||||
self._original_network = original_network
|
||||
self._segments = segments
|
||||
|
||||
@property
|
||||
def current(self):
|
||||
return self._network
|
||||
|
||||
@property
|
||||
def original(self):
|
||||
return self._original_network
|
||||
|
||||
@property
|
||||
def network_segments(self):
|
||||
if not self._segments:
|
||||
self._segments = self._plugin.get_network_segments(
|
||||
@ -48,6 +51,22 @@ class NetworkContext(MechanismDriverContext, api.NetworkContext):
|
||||
return self._segments
|
||||
|
||||
|
||||
class SubnetContext(MechanismDriverContext, api.SubnetContext):
|
||||
|
||||
def __init__(self, plugin, plugin_context, subnet, original_subnet=None):
|
||||
super(SubnetContext, self).__init__(plugin, plugin_context)
|
||||
self._subnet = subnet
|
||||
self._original_subnet = original_subnet
|
||||
|
||||
@property
|
||||
def current(self):
|
||||
return self._subnet
|
||||
|
||||
@property
|
||||
def original(self):
|
||||
return self._original_subnet
|
||||
|
||||
|
||||
class PortContext(MechanismDriverContext, api.PortContext):
|
||||
|
||||
def __init__(self, plugin, plugin_context, port,
|
||||
@ -57,12 +76,15 @@ class PortContext(MechanismDriverContext, api.PortContext):
|
||||
self._original_port = original_port
|
||||
self._network_context = None
|
||||
|
||||
@property
|
||||
def current(self):
|
||||
return self._port
|
||||
|
||||
@property
|
||||
def original(self):
|
||||
return self._original_port
|
||||
|
||||
@property
|
||||
def network(self):
|
||||
"""Return the NetworkContext associated with this port."""
|
||||
if not self._network_context:
|
||||
|
@ -270,6 +270,92 @@ class MechanismManager(stevedore.named.NamedExtensionManager):
|
||||
self._call_on_drivers("delete_network_postcommit", context,
|
||||
continue_on_failure=True)
|
||||
|
||||
def create_subnet_precommit(self, context):
|
||||
"""Notify all mechanism drivers of a subnet creation.
|
||||
|
||||
:raises: neutron.plugins.ml2.common.MechanismDriverError
|
||||
if any mechanism driver create_subnet_precommit call fails.
|
||||
|
||||
Called within the database transaction. If a mechanism driver
|
||||
raises an exception, then a MechanismDriverError is propogated
|
||||
to the caller, triggering a rollback. There is no guarantee
|
||||
that all mechanism drivers are called in this case.
|
||||
"""
|
||||
self._call_on_drivers("create_subnet_precommit", context)
|
||||
|
||||
def create_subnet_postcommit(self, context):
|
||||
"""Notify all mechanism drivers of subnet creation.
|
||||
|
||||
:raises: neutron.plugins.ml2.common.MechanismDriverError
|
||||
if any mechanism driver create_subnet_postcommit call fails.
|
||||
|
||||
Called after the database transaction. If a mechanism driver
|
||||
raises an exception, then a MechanismDriverError is propagated
|
||||
to the caller, where the subnet will be deleted, triggering
|
||||
any required cleanup. There is no guarantee that all mechanism
|
||||
drivers are called in this case.
|
||||
"""
|
||||
self._call_on_drivers("create_subnet_postcommit", context)
|
||||
|
||||
def update_subnet_precommit(self, context):
|
||||
"""Notify all mechanism drivers of a subnet update.
|
||||
|
||||
:raises: neutron.plugins.ml2.common.MechanismDriverError
|
||||
if any mechanism driver update_subnet_precommit call fails.
|
||||
|
||||
Called within the database transaction. If a mechanism driver
|
||||
raises an exception, then a MechanismDriverError is propogated
|
||||
to the caller, triggering a rollback. There is no guarantee
|
||||
that all mechanism drivers are called in this case.
|
||||
"""
|
||||
self._call_on_drivers("update_subnet_precommit", context)
|
||||
|
||||
def update_subnet_postcommit(self, context):
|
||||
"""Notify all mechanism drivers of a subnet update.
|
||||
|
||||
:raises: neutron.plugins.ml2.common.MechanismDriverError
|
||||
if any mechanism driver update_subnet_postcommit call fails.
|
||||
|
||||
Called after the database transaction. If a mechanism driver
|
||||
raises an exception, then a MechanismDriverError is propagated
|
||||
to the caller, where an error is returned to the user. The
|
||||
user is expected to take the appropriate action, whether by
|
||||
retrying the call or deleting the subnet. There is no
|
||||
guarantee that all mechanism drivers are called in this case.
|
||||
"""
|
||||
self._call_on_drivers("update_subnet_postcommit", context)
|
||||
|
||||
def delete_subnet_precommit(self, context):
|
||||
"""Notify all mechanism drivers of a subnet deletion.
|
||||
|
||||
:raises: neutron.plugins.ml2.common.MechanismDriverError
|
||||
if any mechanism driver delete_subnet_precommit call fails.
|
||||
|
||||
Called within the database transaction. If a mechanism driver
|
||||
raises an exception, then a MechanismDriverError is propogated
|
||||
to the caller, triggering a rollback. There is no guarantee
|
||||
that all mechanism drivers are called in this case.
|
||||
"""
|
||||
self._call_on_drivers("delete_subnet_precommit", context)
|
||||
|
||||
def delete_subnet_postcommit(self, context):
|
||||
"""Notify all mechanism drivers of a subnet deletion.
|
||||
|
||||
:raises: neutron.plugins.ml2.common.MechanismDriverError
|
||||
if any mechanism driver delete_subnet_postcommit call fails.
|
||||
|
||||
Called after the database transaction. If any mechanism driver
|
||||
raises an error, then the error is logged but we continue to
|
||||
call every other mechanism driver. A MechanismDriverError is
|
||||
then reraised at the end to notify the caller of a failure. In
|
||||
general we expect the caller to ignore the error, as the
|
||||
subnet resource has already been deleted from the database
|
||||
and it doesn't make sense to undo the action by recreating the
|
||||
subnet.
|
||||
"""
|
||||
self._call_on_drivers("delete_subnet_postcommit", context,
|
||||
continue_on_failure=True)
|
||||
|
||||
def create_port_precommit(self, context):
|
||||
"""Notify all mechanism drivers of a port creation.
|
||||
|
||||
|
@ -311,6 +311,54 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2,
|
||||
pass
|
||||
self.notifier.network_delete(context, id)
|
||||
|
||||
def create_subnet(self, context, subnet):
|
||||
session = context.session
|
||||
with session.begin(subtransactions=True):
|
||||
result = super(Ml2Plugin, self).create_subnet(context, subnet)
|
||||
mech_context = driver_context.SubnetContext(self, context, result)
|
||||
self.mechanism_manager.create_subnet_precommit(mech_context)
|
||||
|
||||
try:
|
||||
self.mechanism_manager.create_subnet_postcommit(mech_context)
|
||||
except ml2_exc.MechanismDriverError:
|
||||
with excutils.save_and_reraise_exception():
|
||||
LOG.error(_("mechanism_manager.create_subnet failed, "
|
||||
"deleting subnet '%s'"), result['id'])
|
||||
self.delete_subnet(context, result['id'])
|
||||
return result
|
||||
|
||||
def update_subnet(self, context, id, subnet):
|
||||
session = context.session
|
||||
with session.begin(subtransactions=True):
|
||||
original_subnet = super(Ml2Plugin, self).get_subnet(context, id)
|
||||
updated_subnet = super(Ml2Plugin, self).update_subnet(
|
||||
context, id, subnet)
|
||||
mech_context = driver_context.SubnetContext(
|
||||
self, context, updated_subnet, original_subnet=original_subnet)
|
||||
self.mechanism_manager.update_subnet_precommit(mech_context)
|
||||
|
||||
# TODO(apech) - handle errors raised by update_subnet, potentially
|
||||
# by re-calling update_subnet with the previous attributes. For
|
||||
# now the error is propogated to the caller, which is expected to
|
||||
# either undo/retry the operation or delete the resource.
|
||||
self.mechanism_manager.update_subnet_postcommit(mech_context)
|
||||
return updated_subnet
|
||||
|
||||
def delete_subnet(self, context, id):
|
||||
session = context.session
|
||||
with session.begin(subtransactions=True):
|
||||
subnet = self.get_subnet(context, id)
|
||||
mech_context = driver_context.SubnetContext(self, context, subnet)
|
||||
self.mechanism_manager.delete_subnet_precommit(mech_context)
|
||||
super(Ml2Plugin, self).delete_subnet(context, id)
|
||||
try:
|
||||
self.mechanism_manager.delete_subnet_postcommit(mech_context)
|
||||
except ml2_exc.MechanismDriverError:
|
||||
# TODO(apech) - One or more mechanism driver failed to
|
||||
# delete the subnet. Ideally we'd notify the caller of
|
||||
# the fact that an error occurred.
|
||||
pass
|
||||
|
||||
def create_port(self, context, port):
|
||||
attrs = port['port']
|
||||
attrs['status'] = const.PORT_STATUS_DOWN
|
||||
|
@ -33,9 +33,9 @@ class LoggerMechanismDriver(api.MechanismDriver):
|
||||
"(original settings %(original)s) and "
|
||||
"network segments %(segments)s"),
|
||||
{'method': method_name,
|
||||
'current': context.current(),
|
||||
'original': context.original(),
|
||||
'segments': context.network_segments()})
|
||||
'current': context.current,
|
||||
'original': context.original,
|
||||
'segments': context.network_segments})
|
||||
|
||||
def create_network_precommit(self, context):
|
||||
self._log_network_call("create_network_precommit", context)
|
||||
@ -55,14 +55,39 @@ class LoggerMechanismDriver(api.MechanismDriver):
|
||||
def delete_network_postcommit(self, context):
|
||||
self._log_network_call("delete_network_postcommit", context)
|
||||
|
||||
def _log_subnet_call(self, method_name, context):
|
||||
LOG.info(_("%(method)s called with subnet settings %(current)s "
|
||||
"(original settings %(original)s)"),
|
||||
{'method': method_name,
|
||||
'current': context.current,
|
||||
'original': context.original})
|
||||
|
||||
def create_subnet_precommit(self, context):
|
||||
self._log_subnet_call("create_subnet_precommit", context)
|
||||
|
||||
def create_subnet_postcommit(self, context):
|
||||
self._log_subnet_call("create_subnet_postcommit", context)
|
||||
|
||||
def update_subnet_precommit(self, context):
|
||||
self._log_subnet_call("update_subnet_precommit", context)
|
||||
|
||||
def update_subnet_postcommit(self, context):
|
||||
self._log_subnet_call("update_subnet_postcommit", context)
|
||||
|
||||
def delete_subnet_precommit(self, context):
|
||||
self._log_subnet_call("delete_subnet_precommit", context)
|
||||
|
||||
def delete_subnet_postcommit(self, context):
|
||||
self._log_subnet_call("delete_subnet_postcommit", context)
|
||||
|
||||
def _log_port_call(self, method_name, context):
|
||||
network_context = context.network()
|
||||
network_context = context.network
|
||||
LOG.info(_("%(method)s called with port settings %(current)s "
|
||||
"(original settings %(original)s) on network %(network)s"),
|
||||
{'method': method_name,
|
||||
'current': context.current(),
|
||||
'original': context.original(),
|
||||
'network': network_context.current()})
|
||||
'current': context.current,
|
||||
'original': context.original,
|
||||
'network': network_context.current})
|
||||
|
||||
def create_port_precommit(self, context):
|
||||
self._log_port_call("create_port_precommit", context)
|
||||
|
@ -25,12 +25,14 @@ class TestMechanismDriver(api.MechanismDriver):
|
||||
|
||||
def _check_network_context(self, context, original_expected):
|
||||
assert(isinstance(context, driver_context.NetworkContext))
|
||||
assert(context.current())
|
||||
assert(isinstance(context.current, dict))
|
||||
assert(context.current['id'] is not None)
|
||||
if original_expected:
|
||||
assert(context.original())
|
||||
assert(isinstance(context.original, dict))
|
||||
assert(context.current['id'] == context.original['id'])
|
||||
else:
|
||||
assert(not context.original())
|
||||
assert(context.network_segments())
|
||||
assert(not context.original)
|
||||
assert(context.network_segments)
|
||||
|
||||
def create_network_precommit(self, context):
|
||||
self._check_network_context(context, False)
|
||||
@ -50,15 +52,45 @@ class TestMechanismDriver(api.MechanismDriver):
|
||||
def delete_network_postcommit(self, context):
|
||||
self._check_network_context(context, False)
|
||||
|
||||
def _check_subnet_context(self, context, original_expected):
|
||||
assert(isinstance(context, driver_context.SubnetContext))
|
||||
assert(isinstance(context.current, dict))
|
||||
assert(context.current['id'] is not None)
|
||||
if original_expected:
|
||||
assert(isinstance(context.original, dict))
|
||||
assert(context.current['id'] == context.original['id'])
|
||||
else:
|
||||
assert(not context.original)
|
||||
|
||||
def create_subnet_precommit(self, context):
|
||||
self._check_subnet_context(context, False)
|
||||
|
||||
def create_subnet_postcommit(self, context):
|
||||
self._check_subnet_context(context, False)
|
||||
|
||||
def update_subnet_precommit(self, context):
|
||||
self._check_subnet_context(context, True)
|
||||
|
||||
def update_subnet_postcommit(self, context):
|
||||
self._check_subnet_context(context, True)
|
||||
|
||||
def delete_subnet_precommit(self, context):
|
||||
self._check_subnet_context(context, False)
|
||||
|
||||
def delete_subnet_postcommit(self, context):
|
||||
self._check_subnet_context(context, False)
|
||||
|
||||
def _check_port_context(self, context, original_expected):
|
||||
assert(isinstance(context, driver_context.PortContext))
|
||||
assert(context.current())
|
||||
assert(isinstance(context.current, dict))
|
||||
assert(context.current['id'] is not None)
|
||||
if original_expected:
|
||||
assert(context.original())
|
||||
assert(isinstance(context.original, dict))
|
||||
assert(context.current['id'] == context.original['id'])
|
||||
else:
|
||||
assert(not context.original())
|
||||
network_context = context.network()
|
||||
assert(network_context)
|
||||
assert(not context.original)
|
||||
network_context = context.network
|
||||
assert(isinstance(network_context, driver_context.NetworkContext))
|
||||
self._check_network_context(network_context, False)
|
||||
|
||||
def create_port_precommit(self, context):
|
||||
|
Loading…
x
Reference in New Issue
Block a user