[apic_aim] ML2Plus SubnetPool and AddressScope support
Add mechanism driver and extension driver support the the SubnetPool
and AddressScope resources, including ensure_tenant.
Change-Id: Icb00eb223d1e503f946ffba54de51e89ba260a1d
(cherry picked from commit a6b918934a)
			
			
This commit is contained in:
		@@ -19,6 +19,70 @@ import six
 | 
				
			|||||||
from neutron.plugins.ml2 import driver_api
 | 
					from neutron.plugins.ml2 import driver_api
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@six.add_metaclass(abc.ABCMeta)
 | 
				
			||||||
 | 
					class SubnetPoolContext(object):
 | 
				
			||||||
 | 
					    """Context passed to MechanismDrivers for changes to subnet pool
 | 
				
			||||||
 | 
					    resources.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    A SubnetPoolContext instance wraps a subnet pool 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.
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @abc.abstractproperty
 | 
				
			||||||
 | 
					    def current(self):
 | 
				
			||||||
 | 
					        """Return the subnet pool in its current configuration.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Return the subnet pool with all its properties 'current' at
 | 
				
			||||||
 | 
					        the time the context was established.
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        pass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @abc.abstractproperty
 | 
				
			||||||
 | 
					    def original(self):
 | 
				
			||||||
 | 
					        """Return the subnet pool in its original configuration.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Return the subnet pool, with all its properties set to their
 | 
				
			||||||
 | 
					        original values prior to a call to update_address_scope. Method is
 | 
				
			||||||
 | 
					        only valid within calls to update_address_scope_precommit and
 | 
				
			||||||
 | 
					        update_address_scope_postcommit.
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        pass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@six.add_metaclass(abc.ABCMeta)
 | 
				
			||||||
 | 
					class AddressScopeContext(object):
 | 
				
			||||||
 | 
					    """Context passed to MechanismDrivers for changes to address scope
 | 
				
			||||||
 | 
					    resources.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    An AddressScopeContext instance wraps an address scope
 | 
				
			||||||
 | 
					    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.
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @abc.abstractproperty
 | 
				
			||||||
 | 
					    def current(self):
 | 
				
			||||||
 | 
					        """Return the address scope in its current configuration.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Return the address scope with all its properties 'current' at
 | 
				
			||||||
 | 
					        the time the context was established.
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        pass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @abc.abstractproperty
 | 
				
			||||||
 | 
					    def original(self):
 | 
				
			||||||
 | 
					        """Return the address scope in its original configuration.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Return the address scope, with all its properties set to their
 | 
				
			||||||
 | 
					        original values prior to a call to update_address_scope. Method is
 | 
				
			||||||
 | 
					        only valid within calls to update_address_scope_precommit and
 | 
				
			||||||
 | 
					        update_address_scope_postcommit.
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        pass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@six.add_metaclass(abc.ABCMeta)
 | 
					@six.add_metaclass(abc.ABCMeta)
 | 
				
			||||||
class MechanismDriver(driver_api.MechanismDriver):
 | 
					class MechanismDriver(driver_api.MechanismDriver):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -39,9 +103,280 @@ class MechanismDriver(driver_api.MechanismDriver):
 | 
				
			|||||||
        """
 | 
					        """
 | 
				
			||||||
        pass
 | 
					        pass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # TODO(rkukura): Add precommit/postcommit calls for address_scope,
 | 
					    def create_subnetpool_precommit(self, context):
 | 
				
			||||||
    # subnet_pool, and other resources.
 | 
					        """Allocate resources for a new subnet pool.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        :param context: SubnetPoolContext instance describing the new
 | 
				
			||||||
 | 
					        subnet pool.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Create a new subnet pool, 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_subnetpool_postcommit(self, context):
 | 
				
			||||||
 | 
					        """Create a subnet pool.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        :param context: SubnetPoolContext instance describing the new
 | 
				
			||||||
 | 
					        subnet pool.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        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_subnetpool_precommit(self, context):
 | 
				
			||||||
 | 
					        """Update resources of a subnet pool.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        :param context: SubnetPoolContext instance describing the new
 | 
				
			||||||
 | 
					        state of the subnet pool, as well as the original state prior
 | 
				
			||||||
 | 
					        to the update_subnetpool call.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Update values of a subnet pool, updating the associated
 | 
				
			||||||
 | 
					        resources in the database. Called inside transaction context
 | 
				
			||||||
 | 
					        on session.  Raising an exception will result in rollback of
 | 
				
			||||||
 | 
					        the transaction.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        update_subnetpool_precommit is called for all changes to the
 | 
				
			||||||
 | 
					        subnet pool 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_subnetpool_postcommit(self, context):
 | 
				
			||||||
 | 
					        """Update a subnet pool.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        :param context: SubnetPoolContext instance describing the new
 | 
				
			||||||
 | 
					        state of the subnet pool, as well as the original state prior
 | 
				
			||||||
 | 
					        to the update_subnetpool 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_subnetpool_postcommit is called for all changes to the
 | 
				
			||||||
 | 
					        subnet pool 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_subnetpool_precommit(self, context):
 | 
				
			||||||
 | 
					        """Delete resources for a subnet pool.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        :param context: SubnetPoolContext instance describing the
 | 
				
			||||||
 | 
					        current state of the subnet pool, prior to the call to delete
 | 
				
			||||||
 | 
					        it.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Delete subnet pool resources previously allocated by this
 | 
				
			||||||
 | 
					        mechanism driver for a subnet pool. 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_subnetpool_postcommit(self, context):
 | 
				
			||||||
 | 
					        """Delete a subnet pool.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        :param context: SubnetPoolContext instance describing the
 | 
				
			||||||
 | 
					        current state of the subnet pool, 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_address_scope_precommit(self, context):
 | 
				
			||||||
 | 
					        """Allocate resources for a new address scope.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        :param context: AddressScopeContext instance describing the
 | 
				
			||||||
 | 
					        new address scope.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Create a new address scope, 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_address_scope_postcommit(self, context):
 | 
				
			||||||
 | 
					        """Create an address scope.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        :param context: AddressScopeContext instance describing the
 | 
				
			||||||
 | 
					        new address scope.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        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_address_scope_precommit(self, context):
 | 
				
			||||||
 | 
					        """Update resources of an address scope.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        :param context: AddressScopeContext instance describing the
 | 
				
			||||||
 | 
					        new state of the address scope, as well as the original state
 | 
				
			||||||
 | 
					        prior to the update_address_scope call.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Update values of an address scope, updating the associated
 | 
				
			||||||
 | 
					        resources in the database. Called inside transaction context
 | 
				
			||||||
 | 
					        on session.  Raising an exception will result in rollback of
 | 
				
			||||||
 | 
					        the transaction.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        update_address_scope_precommit is called for all changes to
 | 
				
			||||||
 | 
					        the address scope 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_address_scope_postcommit(self, context):
 | 
				
			||||||
 | 
					        """Update an address scope.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        :param context: AddressScopeContext instance describing the
 | 
				
			||||||
 | 
					        new state of the address scope, as well as the original state
 | 
				
			||||||
 | 
					        prior to the update_address_scope 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_address_scope_postcommit is called for all changes to
 | 
				
			||||||
 | 
					        the address scope 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_address_scope_precommit(self, context):
 | 
				
			||||||
 | 
					        """Delete resources for an address scope.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        :param context: AddressScopeContext instance describing the
 | 
				
			||||||
 | 
					        current state of the address scope, prior to the call to
 | 
				
			||||||
 | 
					        delete it.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Delete address scope resources previously allocated by this
 | 
				
			||||||
 | 
					        mechanism driver for an address scope. 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_address_scope_postcommit(self, context):
 | 
				
			||||||
 | 
					        """Delete an address scope.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        :param context: AddressScopeContext instance describing the
 | 
				
			||||||
 | 
					        current state of the address scope, 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
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # REVISIT(rkukura): Add precommit/postcommit calls for other
 | 
				
			||||||
 | 
					    # resources implemented in ML2, such as security groups and
 | 
				
			||||||
 | 
					    # security group rules?
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# TODO(rkukura): Extend ExtensionDriver for address_scope,
 | 
					@six.add_metaclass(abc.ABCMeta)
 | 
				
			||||||
# subnet_pool, and other resources.
 | 
					class ExtensionDriver(driver_api.ExtensionDriver):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def process_create_subnetpool(self, plugin_context, data, result):
 | 
				
			||||||
 | 
					        """Process extended attributes for create subnet pool.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        :param plugin_context: plugin request context
 | 
				
			||||||
 | 
					        :param data: dictionary of incoming subnet pool data
 | 
				
			||||||
 | 
					        :param result: subnet pool dictionary to extend
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Called inside transaction context on plugin_context.session to
 | 
				
			||||||
 | 
					        validate and persist any extended subnet pool attributes
 | 
				
			||||||
 | 
					        defined by this driver. Extended attribute values must also be
 | 
				
			||||||
 | 
					        added to result.
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        pass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def process_update_subnetpool(self, plugin_context, data, result):
 | 
				
			||||||
 | 
					        """Process extended attributes for update subnet pool.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        :param plugin_context: plugin request context
 | 
				
			||||||
 | 
					        :param data: dictionary of incoming subnet pool data
 | 
				
			||||||
 | 
					        :param result: subnet pool dictionary to extend
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Called inside transaction context on plugin_context.session to
 | 
				
			||||||
 | 
					        validate and update any extended subnet pool attributes
 | 
				
			||||||
 | 
					        defined by this driver. Extended attribute values, whether
 | 
				
			||||||
 | 
					        updated or not, must also be added to result.
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        pass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def extend_subnetpool_dict(self, session, base_model, result):
 | 
				
			||||||
 | 
					        """Add extended attributes to subnet pool dictionary.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        :param session: database session
 | 
				
			||||||
 | 
					        :param base_model: subnet pool model data
 | 
				
			||||||
 | 
					        :param result: subnet pool dictionary to extend
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Called inside transaction context on session to add any
 | 
				
			||||||
 | 
					        extended attributes defined by this driver to a subnet pool
 | 
				
			||||||
 | 
					        dictionary to be used for mechanism driver calls and/or
 | 
				
			||||||
 | 
					        returned as the result of a subnet pool operation.
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        pass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def process_create_address_scope(self, plugin_context, data, result):
 | 
				
			||||||
 | 
					        """Process extended attributes for create address scope.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        :param plugin_context: plugin request context
 | 
				
			||||||
 | 
					        :param data: dictionary of incoming address scope data
 | 
				
			||||||
 | 
					        :param result: address scope dictionary to extend
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Called inside transaction context on plugin_context.session to
 | 
				
			||||||
 | 
					        validate and persist any extended address scope attributes
 | 
				
			||||||
 | 
					        defined by this driver. Extended attribute values must also be
 | 
				
			||||||
 | 
					        added to result.
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        pass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def process_update_address_scope(self, plugin_context, data, result):
 | 
				
			||||||
 | 
					        """Process extended attributes for update address scope.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        :param plugin_context: plugin request context
 | 
				
			||||||
 | 
					        :param data: dictionary of incoming address scope data
 | 
				
			||||||
 | 
					        :param result: address scope dictionary to extend
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Called inside transaction context on plugin_context.session to
 | 
				
			||||||
 | 
					        validate and update any extended address scope attributes
 | 
				
			||||||
 | 
					        defined by this driver. Extended attribute values, whether
 | 
				
			||||||
 | 
					        updated or not, must also be added to result.
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        pass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def extend_address_scope_dict(self, session, base_model, result):
 | 
				
			||||||
 | 
					        """Add extended attributes to address scope dictionary.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        :param session: database session
 | 
				
			||||||
 | 
					        :param base_model: address scope model data
 | 
				
			||||||
 | 
					        :param result: address scope dictionary to extend
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Called inside transaction context on session to add any
 | 
				
			||||||
 | 
					        extended attributes defined by this driver to an address scope
 | 
				
			||||||
 | 
					        dictionary to be used for mechanism driver calls and/or
 | 
				
			||||||
 | 
					        returned as the result of an address scope operation.
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        pass
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										54
									
								
								gbpservice/neutron/plugins/ml2plus/driver_context.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										54
									
								
								gbpservice/neutron/plugins/ml2plus/driver_context.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,54 @@
 | 
				
			|||||||
 | 
					# Copyright (c) 2016 Cisco Systems 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 neutron.plugins.ml2 import driver_context as ml2_context
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from gbpservice.neutron.plugins.ml2plus import driver_api as api
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class SubnetPoolContext(ml2_context.MechanismDriverContext,
 | 
				
			||||||
 | 
					                        api.SubnetPoolContext):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __init__(self, plugin, plugin_context, subnetpool,
 | 
				
			||||||
 | 
					                 original_subnetpool=None):
 | 
				
			||||||
 | 
					        super(SubnetPoolContext, self).__init__(plugin, plugin_context)
 | 
				
			||||||
 | 
					        self._subnetpool = subnetpool
 | 
				
			||||||
 | 
					        self._original_subnetpool = original_subnetpool
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @property
 | 
				
			||||||
 | 
					    def current(self):
 | 
				
			||||||
 | 
					        return self._subnetpool
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @property
 | 
				
			||||||
 | 
					    def original(self):
 | 
				
			||||||
 | 
					        return self._original_subnetpool
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class AddressScopeContext(ml2_context.MechanismDriverContext,
 | 
				
			||||||
 | 
					                          api.AddressScopeContext):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __init__(self, plugin, plugin_context, address_scope,
 | 
				
			||||||
 | 
					                 original_address_scope=None):
 | 
				
			||||||
 | 
					        super(AddressScopeContext, self).__init__(plugin, plugin_context)
 | 
				
			||||||
 | 
					        self._address_scope = address_scope
 | 
				
			||||||
 | 
					        self._original_address_scope = original_address_scope
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @property
 | 
				
			||||||
 | 
					    def current(self):
 | 
				
			||||||
 | 
					        return self._address_scope
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @property
 | 
				
			||||||
 | 
					    def original(self):
 | 
				
			||||||
 | 
					        return self._original_address_scope
 | 
				
			||||||
@@ -0,0 +1,23 @@
 | 
				
			|||||||
 | 
					# Copyright (c) 2016 Cisco Systems 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 neutron.extensions import address_scope
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Patched_address_scope(address_scope.Address_scope):
 | 
				
			||||||
 | 
					    def update_attributes_map(self, attributes):
 | 
				
			||||||
 | 
					        super(Patched_address_scope, self).update_attributes_map(
 | 
				
			||||||
 | 
					            attributes,
 | 
				
			||||||
 | 
					            extension_attrs_map=address_scope.RESOURCE_ATTRIBUTE_MAP)
 | 
				
			||||||
@@ -16,9 +16,11 @@
 | 
				
			|||||||
from gbpservice.neutron.plugins.ml2plus import driver_api
 | 
					from gbpservice.neutron.plugins.ml2plus import driver_api
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from neutron._i18n import _LE
 | 
					from neutron._i18n import _LE
 | 
				
			||||||
 | 
					from neutron._i18n import _LI
 | 
				
			||||||
from neutron.plugins.ml2.common import exceptions as ml2_exc
 | 
					from neutron.plugins.ml2.common import exceptions as ml2_exc
 | 
				
			||||||
from neutron.plugins.ml2 import managers
 | 
					from neutron.plugins.ml2 import managers
 | 
				
			||||||
from oslo_log import log
 | 
					from oslo_log import log
 | 
				
			||||||
 | 
					from oslo_utils import excutils
 | 
				
			||||||
 | 
					
 | 
				
			||||||
LOG = log.getLogger(__name__)
 | 
					LOG = log.getLogger(__name__)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -28,6 +30,37 @@ class MechanismManager(managers.MechanismManager):
 | 
				
			|||||||
    def __init__(self):
 | 
					    def __init__(self):
 | 
				
			||||||
        super(MechanismManager, self).__init__()
 | 
					        super(MechanismManager, self).__init__()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def _call_on_extended_drivers(self, method_name, context,
 | 
				
			||||||
 | 
					                                  continue_on_failure=False):
 | 
				
			||||||
 | 
					        """Call a method on all extended mechanism drivers.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        :param method_name: name of the method to call
 | 
				
			||||||
 | 
					        :param context: context parameter to pass to each method call
 | 
				
			||||||
 | 
					        :param continue_on_failure: whether or not to continue to call
 | 
				
			||||||
 | 
					        all mechanism drivers once one has raised an exception
 | 
				
			||||||
 | 
					        :raises: neutron.plugins.ml2.common.MechanismDriverError
 | 
				
			||||||
 | 
					        if any mechanism driver call fails.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        error = False
 | 
				
			||||||
 | 
					        for driver in self.ordered_mech_drivers:
 | 
				
			||||||
 | 
					            if isinstance(driver.obj, driver_api.MechanismDriver):
 | 
				
			||||||
 | 
					                try:
 | 
				
			||||||
 | 
					                    getattr(driver.obj, method_name)(context)
 | 
				
			||||||
 | 
					                except Exception:
 | 
				
			||||||
 | 
					                    LOG.exception(
 | 
				
			||||||
 | 
					                        _LE("Mechanism driver '%(name)s' failed in "
 | 
				
			||||||
 | 
					                            "%(method)s"),
 | 
				
			||||||
 | 
					                        {'name': driver.name, 'method': method_name}
 | 
				
			||||||
 | 
					                    )
 | 
				
			||||||
 | 
					                    error = True
 | 
				
			||||||
 | 
					                    if not continue_on_failure:
 | 
				
			||||||
 | 
					                        break
 | 
				
			||||||
 | 
					        if error:
 | 
				
			||||||
 | 
					            raise ml2_exc.MechanismDriverError(
 | 
				
			||||||
 | 
					                method=method_name
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def ensure_tenant(self, plugin_context, tenant_id):
 | 
					    def ensure_tenant(self, plugin_context, tenant_id):
 | 
				
			||||||
        for driver in self.ordered_mech_drivers:
 | 
					        for driver in self.ordered_mech_drivers:
 | 
				
			||||||
            if isinstance(driver.obj, driver_api.MechanismDriver):
 | 
					            if isinstance(driver.obj, driver_api.MechanismDriver):
 | 
				
			||||||
@@ -37,3 +70,108 @@ class MechanismManager(managers.MechanismManager):
 | 
				
			|||||||
                    LOG.exception(_LE("Mechanism driver '%s' failed in "
 | 
					                    LOG.exception(_LE("Mechanism driver '%s' failed in "
 | 
				
			||||||
                                      "ensure_tenant"), driver.name)
 | 
					                                      "ensure_tenant"), driver.name)
 | 
				
			||||||
                    raise ml2_exc.MechanismDriverError(method="ensure_tenant")
 | 
					                    raise ml2_exc.MechanismDriverError(method="ensure_tenant")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def create_subnetpool_precommit(self, context):
 | 
				
			||||||
 | 
					        self._call_on_extended_drivers("create_subnetpool_precommit",
 | 
				
			||||||
 | 
					                                       context)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def create_subnetpool_postcommit(self, context):
 | 
				
			||||||
 | 
					        self._call_on_extended_drivers("create_subnetpool_postcommit",
 | 
				
			||||||
 | 
					                                       context)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def update_subnetpool_precommit(self, context):
 | 
				
			||||||
 | 
					        self._call_on_extended_drivers("update_subnetpool_precommit",
 | 
				
			||||||
 | 
					                                       context)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def update_subnetpool_postcommit(self, context):
 | 
				
			||||||
 | 
					        self._call_on_extended_drivers("update_subnetpool_postcommit",
 | 
				
			||||||
 | 
					                                       context)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def delete_subnetpool_precommit(self, context):
 | 
				
			||||||
 | 
					        self._call_on_extended_drivers("delete_subnetpool_precommit",
 | 
				
			||||||
 | 
					                                       context)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def delete_subnetpool_postcommit(self, context):
 | 
				
			||||||
 | 
					        self._call_on_extended_drivers("delete_subnetpool_postcommit",
 | 
				
			||||||
 | 
					                                       context)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def create_address_scope_precommit(self, context):
 | 
				
			||||||
 | 
					        self._call_on_extended_drivers("create_address_scope_precommit",
 | 
				
			||||||
 | 
					                                       context)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def create_address_scope_postcommit(self, context):
 | 
				
			||||||
 | 
					        self._call_on_extended_drivers("create_address_scope_postcommit",
 | 
				
			||||||
 | 
					                                       context)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def update_address_scope_precommit(self, context):
 | 
				
			||||||
 | 
					        self._call_on_extended_drivers("update_address_scope_precommit",
 | 
				
			||||||
 | 
					                                       context)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def update_address_scope_postcommit(self, context):
 | 
				
			||||||
 | 
					        self._call_on_extended_drivers("update_address_scope_postcommit",
 | 
				
			||||||
 | 
					                                       context)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def delete_address_scope_precommit(self, context):
 | 
				
			||||||
 | 
					        self._call_on_extended_drivers("delete_address_scope_precommit",
 | 
				
			||||||
 | 
					                                       context)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def delete_address_scope_postcommit(self, context):
 | 
				
			||||||
 | 
					        self._call_on_extended_drivers("delete_address_scope_postcommit",
 | 
				
			||||||
 | 
					                                       context)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class ExtensionManager(managers.ExtensionManager):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __init__(self):
 | 
				
			||||||
 | 
					        super(ExtensionManager, self).__init__()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def _call_on_extended_drivers(self, method_name, plugin_context, data,
 | 
				
			||||||
 | 
					                                  result):
 | 
				
			||||||
 | 
					        """Call a method on all extended extension drivers."""
 | 
				
			||||||
 | 
					        for driver in self.ordered_ext_drivers:
 | 
				
			||||||
 | 
					            if isinstance(driver.obj, driver_api.ExtensionDriver):
 | 
				
			||||||
 | 
					                try:
 | 
				
			||||||
 | 
					                    getattr(driver.obj, method_name)(plugin_context, data,
 | 
				
			||||||
 | 
					                                                     result)
 | 
				
			||||||
 | 
					                except Exception:
 | 
				
			||||||
 | 
					                    with excutils.save_and_reraise_exception():
 | 
				
			||||||
 | 
					                        LOG.info(_LI("Extension driver '%(name)s' failed in "
 | 
				
			||||||
 | 
					                                     "%(method)s"),
 | 
				
			||||||
 | 
					                                 {'name': driver.name, 'method': method_name})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def _call_on_dict_extended_drivers(self, method_name, session, base_model,
 | 
				
			||||||
 | 
					                                       result):
 | 
				
			||||||
 | 
					        for driver in self.ordered_ext_drivers:
 | 
				
			||||||
 | 
					            if isinstance(driver.obj, driver_api.ExtensionDriver):
 | 
				
			||||||
 | 
					                try:
 | 
				
			||||||
 | 
					                    getattr(driver.obj, method_name)(session, base_model,
 | 
				
			||||||
 | 
					                                                     result)
 | 
				
			||||||
 | 
					                except Exception:
 | 
				
			||||||
 | 
					                    LOG.error(_LE("Extension driver '%(name)s' failed in "
 | 
				
			||||||
 | 
					                                  "%(method)s"),
 | 
				
			||||||
 | 
					                              {'name': driver.name, 'method': method_name})
 | 
				
			||||||
 | 
					                    raise ml2_exc.ExtensionDriverError(driver=driver.name)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def process_create_subnetpool(self, plugin_context, data, result):
 | 
				
			||||||
 | 
					        self._call_on_extended_drivers("process_create_subnetpool",
 | 
				
			||||||
 | 
					                                       plugin_context, data, result)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def process_update_subnetpool(self, plugin_context, data, result):
 | 
				
			||||||
 | 
					        self._call_on_extended_drivers("process_update_subnetpool",
 | 
				
			||||||
 | 
					                                       plugin_context, data, result)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def extend_subnetpool_dict(self, session, base_model, result):
 | 
				
			||||||
 | 
					        self._call_on_dict_extended_drivers("extend_subnetpool_dict",
 | 
				
			||||||
 | 
					                                            session, base_model, result)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def process_create_address_scope(self, plugin_context, data, result):
 | 
				
			||||||
 | 
					        self._call_on_extended_drivers("process_create_address_scope",
 | 
				
			||||||
 | 
					                                       plugin_context, data, result)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def process_update_address_scope(self, plugin_context, data, result):
 | 
				
			||||||
 | 
					        self._call_on_extended_drivers("process_update_address_scope",
 | 
				
			||||||
 | 
					                                       plugin_context, data, result)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def extend_address_scope_dict(self, session, base_model, result):
 | 
				
			||||||
 | 
					        self._call_on_dict_extended_drivers("extend_address_scope_dict",
 | 
				
			||||||
 | 
					                                            session, base_model, result)
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										32
									
								
								gbpservice/neutron/plugins/ml2plus/patch_neutron.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								gbpservice/neutron/plugins/ml2plus/patch_neutron.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,32 @@
 | 
				
			|||||||
 | 
					# Copyright (c) 2016 Cisco Systems 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 neutron.api import extensions
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from gbpservice.neutron.plugins.ml2plus import extension_overrides
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Monkeypatch Neutron to allow overriding its own extension
 | 
				
			||||||
 | 
					# descriptors. Note that extension descriptor classes cannot be
 | 
				
			||||||
 | 
					# monkeypatched directly because they are loaded explicitly by file
 | 
				
			||||||
 | 
					# name and then used immediately.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					_real_get_extensions_path = extensions.get_extensions_path
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def get_extensions_path(service_plugins=None):
 | 
				
			||||||
 | 
					    path = _real_get_extensions_path(service_plugins)
 | 
				
			||||||
 | 
					    return extension_overrides.__path__[0] + ':' + path
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extensions.get_extensions_path = get_extensions_path
 | 
				
			||||||
@@ -13,17 +13,24 @@
 | 
				
			|||||||
#    License for the specific language governing permissions and limitations
 | 
					#    License for the specific language governing permissions and limitations
 | 
				
			||||||
#    under the License.
 | 
					#    under the License.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from neutron._i18n import _LE
 | 
				
			||||||
from neutron._i18n import _LI
 | 
					from neutron._i18n import _LI
 | 
				
			||||||
from neutron.api.v2 import attributes
 | 
					from neutron.api.v2 import attributes
 | 
				
			||||||
 | 
					from neutron.db import db_base_plugin_v2
 | 
				
			||||||
from neutron.db import models_v2
 | 
					from neutron.db import models_v2
 | 
				
			||||||
from neutron.db import securitygroups_db
 | 
					from neutron.db import securitygroups_db
 | 
				
			||||||
 | 
					from neutron.extensions import address_scope as as_ext
 | 
				
			||||||
 | 
					from neutron.plugins.ml2.common import exceptions as ml2_exc
 | 
				
			||||||
from neutron.plugins.ml2 import managers as ml2_managers
 | 
					from neutron.plugins.ml2 import managers as ml2_managers
 | 
				
			||||||
from neutron.plugins.ml2 import plugin as ml2_plugin
 | 
					from neutron.plugins.ml2 import plugin as ml2_plugin
 | 
				
			||||||
from neutron.quota import resource_registry
 | 
					from neutron.quota import resource_registry
 | 
				
			||||||
from oslo_log import log
 | 
					from oslo_log import log
 | 
				
			||||||
 | 
					from oslo_utils import excutils
 | 
				
			||||||
from sqlalchemy import inspect
 | 
					from sqlalchemy import inspect
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from gbpservice.neutron.plugins.ml2plus import driver_context
 | 
				
			||||||
from gbpservice.neutron.plugins.ml2plus import managers
 | 
					from gbpservice.neutron.plugins.ml2plus import managers
 | 
				
			||||||
 | 
					from gbpservice.neutron.plugins.ml2plus import patch_neutron  # noqa
 | 
				
			||||||
 | 
					
 | 
				
			||||||
LOG = log.getLogger(__name__)
 | 
					LOG = log.getLogger(__name__)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -59,7 +66,7 @@ class Ml2PlusPlugin(ml2_plugin.Ml2Plugin):
 | 
				
			|||||||
        LOG.info(_LI("Ml2Plus initializing"))
 | 
					        LOG.info(_LI("Ml2Plus initializing"))
 | 
				
			||||||
        # First load drivers, then initialize DB, then initialize drivers
 | 
					        # First load drivers, then initialize DB, then initialize drivers
 | 
				
			||||||
        self.type_manager = ml2_managers.TypeManager()
 | 
					        self.type_manager = ml2_managers.TypeManager()
 | 
				
			||||||
        self.extension_manager = ml2_managers.ExtensionManager()
 | 
					        self.extension_manager = managers.ExtensionManager()
 | 
				
			||||||
        self.mechanism_manager = managers.MechanismManager()
 | 
					        self.mechanism_manager = managers.MechanismManager()
 | 
				
			||||||
        super(ml2_plugin.Ml2Plugin, self).__init__()
 | 
					        super(ml2_plugin.Ml2Plugin, self).__init__()
 | 
				
			||||||
        self.type_manager.initialize()
 | 
					        self.type_manager.initialize()
 | 
				
			||||||
@@ -71,6 +78,12 @@ class Ml2PlusPlugin(ml2_plugin.Ml2Plugin):
 | 
				
			|||||||
        self._verify_service_plugins_requirements()
 | 
					        self._verify_service_plugins_requirements()
 | 
				
			||||||
        LOG.info(_LI("Modular L2 Plugin (extended) initialization complete"))
 | 
					        LOG.info(_LI("Modular L2 Plugin (extended) initialization complete"))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    db_base_plugin_v2.NeutronDbPluginV2.register_dict_extend_funcs(
 | 
				
			||||||
 | 
					               attributes.SUBNETPOOLS, ['_ml2_md_extend_subnetpool_dict'])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    db_base_plugin_v2.NeutronDbPluginV2.register_dict_extend_funcs(
 | 
				
			||||||
 | 
					               as_ext.ADDRESS_SCOPES, ['_ml2_md_extend_address_scope_dict'])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def _ml2_md_extend_network_dict(self, result, netdb):
 | 
					    def _ml2_md_extend_network_dict(self, result, netdb):
 | 
				
			||||||
        session = inspect(netdb).session
 | 
					        session = inspect(netdb).session
 | 
				
			||||||
        with session.begin(subtransactions=True):
 | 
					        with session.begin(subtransactions=True):
 | 
				
			||||||
@@ -87,6 +100,29 @@ class Ml2PlusPlugin(ml2_plugin.Ml2Plugin):
 | 
				
			|||||||
            self.extension_manager.extend_subnet_dict(
 | 
					            self.extension_manager.extend_subnet_dict(
 | 
				
			||||||
                session, subnetdb, result)
 | 
					                session, subnetdb, result)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def _ml2_md_extend_subnetpool_dict(self, result, subnetpooldb):
 | 
				
			||||||
 | 
					        session = inspect(subnetpooldb).session
 | 
				
			||||||
 | 
					        with session.begin(subtransactions=True):
 | 
				
			||||||
 | 
					            self.extension_manager.extend_subnetpool_dict(
 | 
				
			||||||
 | 
					                session, subnetpooldb, result)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def _ml2_md_extend_address_scope_dict(self, result, address_scopedb):
 | 
				
			||||||
 | 
					        session = inspect(address_scopedb).session
 | 
				
			||||||
 | 
					        with session.begin(subtransactions=True):
 | 
				
			||||||
 | 
					            self.extension_manager.extend_address_scope_dict(
 | 
				
			||||||
 | 
					                session, address_scopedb, result)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # Base version does not call _apply_dict_extend_functions()
 | 
				
			||||||
 | 
					    def _make_address_scope_dict(self, address_scope, fields=None):
 | 
				
			||||||
 | 
					        res = {'id': address_scope['id'],
 | 
				
			||||||
 | 
					               'name': address_scope['name'],
 | 
				
			||||||
 | 
					               'tenant_id': address_scope['tenant_id'],
 | 
				
			||||||
 | 
					               'shared': address_scope['shared'],
 | 
				
			||||||
 | 
					               'ip_version': address_scope['ip_version']}
 | 
				
			||||||
 | 
					        self._apply_dict_extend_functions(as_ext.ADDRESS_SCOPES, res,
 | 
				
			||||||
 | 
					                                          address_scope)
 | 
				
			||||||
 | 
					        return self._fields(res, fields)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def create_network(self, context, network):
 | 
					    def create_network(self, context, network):
 | 
				
			||||||
        self._ensure_tenant(context, network[attributes.NETWORK])
 | 
					        self._ensure_tenant(context, network[attributes.NETWORK])
 | 
				
			||||||
        return super(Ml2PlusPlugin, self).create_network(context, network)
 | 
					        return super(Ml2PlusPlugin, self).create_network(context, network)
 | 
				
			||||||
@@ -117,9 +153,110 @@ class Ml2PlusPlugin(ml2_plugin.Ml2Plugin):
 | 
				
			|||||||
        return super(Ml2PlusPlugin, self).create_port_bulk(context,
 | 
					        return super(Ml2PlusPlugin, self).create_port_bulk(context,
 | 
				
			||||||
                                                           ports)
 | 
					                                                           ports)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # TODO(rkukura): Override address_scope, subnet_pool, and any
 | 
					    def create_subnetpool(self, context, subnetpool):
 | 
				
			||||||
    # other needed resources to ensure tenant and invoke mechanism and
 | 
					        self._ensure_tenant(context, subnetpool[attributes.SUBNETPOOL])
 | 
				
			||||||
    # extension drivers.
 | 
					        session = context.session
 | 
				
			||||||
 | 
					        with session.begin(subtransactions=True):
 | 
				
			||||||
 | 
					            result = super(Ml2PlusPlugin, self).create_subnetpool(context,
 | 
				
			||||||
 | 
					                                                                  subnetpool)
 | 
				
			||||||
 | 
					            self.extension_manager.process_create_subnetpool(
 | 
				
			||||||
 | 
					                context, subnetpool[attributes.SUBNETPOOL], result)
 | 
				
			||||||
 | 
					            mech_context = driver_context.SubnetPoolContext(
 | 
				
			||||||
 | 
					                self, context, result)
 | 
				
			||||||
 | 
					            self.mechanism_manager.create_subnetpool_precommit(mech_context)
 | 
				
			||||||
 | 
					        try:
 | 
				
			||||||
 | 
					            self.mechanism_manager.create_subnetpool_postcommit(mech_context)
 | 
				
			||||||
 | 
					        except ml2_exc.MechanismDriverError:
 | 
				
			||||||
 | 
					            with excutils.save_and_reraise_exception():
 | 
				
			||||||
 | 
					                LOG.error(_LE("mechanism_manager.create_subnetpool_postcommit "
 | 
				
			||||||
 | 
					                              "failed, deleting subnetpool '%s'"),
 | 
				
			||||||
 | 
					                          result['id'])
 | 
				
			||||||
 | 
					                self.delete_subnetpool(context, result['id'])
 | 
				
			||||||
 | 
					        return result
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # REVISIT(rkukura): Is create_subnetpool_bulk() needed?
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def update_subnetpool(self, context, id, subnetpool):
 | 
				
			||||||
 | 
					        session = context.session
 | 
				
			||||||
 | 
					        with session.begin(subtransactions=True):
 | 
				
			||||||
 | 
					            original_subnetpool = super(Ml2PlusPlugin, self).get_subnetpool(
 | 
				
			||||||
 | 
					                context, id)
 | 
				
			||||||
 | 
					            updated_subnetpool = super(Ml2PlusPlugin, self).update_subnetpool(
 | 
				
			||||||
 | 
					                context, id, subnetpool)
 | 
				
			||||||
 | 
					            self.extension_manager.process_update_subnetpool(
 | 
				
			||||||
 | 
					                context, subnetpool[attributes.SUBNETPOOL],
 | 
				
			||||||
 | 
					                updated_subnetpool)
 | 
				
			||||||
 | 
					            mech_context = driver_context.SubnetPoolContext(
 | 
				
			||||||
 | 
					                self, context, updated_subnetpool,
 | 
				
			||||||
 | 
					                original_subnetpool=original_subnetpool)
 | 
				
			||||||
 | 
					            self.mechanism_manager.update_subnetpool_precommit(mech_context)
 | 
				
			||||||
 | 
					        self.mechanism_manager.update_subnetpool_postcommit(mech_context)
 | 
				
			||||||
 | 
					        return updated_subnetpool
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def delete_subnetpool(self, context, id):
 | 
				
			||||||
 | 
					        session = context.session
 | 
				
			||||||
 | 
					        with session.begin(subtransactions=True):
 | 
				
			||||||
 | 
					            subnetpool = super(Ml2PlusPlugin, self).get_subnetpool(context, id)
 | 
				
			||||||
 | 
					            super(Ml2PlusPlugin, self).delete_subnetpool(context, id)
 | 
				
			||||||
 | 
					            mech_context = driver_context.SubnetPoolContext(
 | 
				
			||||||
 | 
					                self, context, subnetpool)
 | 
				
			||||||
 | 
					            self.mechanism_manager.delete_subnetpool_precommit(mech_context)
 | 
				
			||||||
 | 
					        self.mechanism_manager.delete_subnetpool_postcommit(mech_context)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def create_address_scope(self, context, address_scope):
 | 
				
			||||||
 | 
					        self._ensure_tenant(context, address_scope[as_ext.ADDRESS_SCOPE])
 | 
				
			||||||
 | 
					        session = context.session
 | 
				
			||||||
 | 
					        with session.begin(subtransactions=True):
 | 
				
			||||||
 | 
					            result = super(Ml2PlusPlugin, self).create_address_scope(
 | 
				
			||||||
 | 
					                context, address_scope)
 | 
				
			||||||
 | 
					            self.extension_manager.process_create_address_scope(
 | 
				
			||||||
 | 
					                context, address_scope[as_ext.ADDRESS_SCOPE], result)
 | 
				
			||||||
 | 
					            mech_context = driver_context.AddressScopeContext(
 | 
				
			||||||
 | 
					                self, context, result)
 | 
				
			||||||
 | 
					            self.mechanism_manager.create_address_scope_precommit(
 | 
				
			||||||
 | 
					                mech_context)
 | 
				
			||||||
 | 
					        try:
 | 
				
			||||||
 | 
					            self.mechanism_manager.create_address_scope_postcommit(
 | 
				
			||||||
 | 
					                mech_context)
 | 
				
			||||||
 | 
					        except ml2_exc.MechanismDriverError:
 | 
				
			||||||
 | 
					            with excutils.save_and_reraise_exception():
 | 
				
			||||||
 | 
					                LOG.error(_LE("mechanism_manager.create_address_scope_"
 | 
				
			||||||
 | 
					                              "postcommit failed, deleting address_scope"
 | 
				
			||||||
 | 
					                              " '%s'"),
 | 
				
			||||||
 | 
					                          result['id'])
 | 
				
			||||||
 | 
					                self.delete_address_scope(context, result['id'])
 | 
				
			||||||
 | 
					        return result
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # REVISIT(rkukura): Is create_address_scope_bulk() needed?
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def update_address_scope(self, context, id, address_scope):
 | 
				
			||||||
 | 
					        session = context.session
 | 
				
			||||||
 | 
					        with session.begin(subtransactions=True):
 | 
				
			||||||
 | 
					            original_address_scope = super(Ml2PlusPlugin,
 | 
				
			||||||
 | 
					                                           self).get_address_scope(context, id)
 | 
				
			||||||
 | 
					            updated_address_scope = super(Ml2PlusPlugin,
 | 
				
			||||||
 | 
					                                          self).update_address_scope(
 | 
				
			||||||
 | 
					                                              context, id, address_scope)
 | 
				
			||||||
 | 
					            self.extension_manager.process_update_address_scope(
 | 
				
			||||||
 | 
					                context, address_scope[as_ext.ADDRESS_SCOPE],
 | 
				
			||||||
 | 
					                updated_address_scope)
 | 
				
			||||||
 | 
					            mech_context = driver_context.AddressScopeContext(
 | 
				
			||||||
 | 
					                self, context, updated_address_scope,
 | 
				
			||||||
 | 
					                original_address_scope=original_address_scope)
 | 
				
			||||||
 | 
					            self.mechanism_manager.update_address_scope_precommit(mech_context)
 | 
				
			||||||
 | 
					        self.mechanism_manager.update_address_scope_postcommit(mech_context)
 | 
				
			||||||
 | 
					        return updated_address_scope
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def delete_address_scope(self, context, id):
 | 
				
			||||||
 | 
					        session = context.session
 | 
				
			||||||
 | 
					        with session.begin(subtransactions=True):
 | 
				
			||||||
 | 
					            address_scope = super(Ml2PlusPlugin, self).get_address_scope(
 | 
				
			||||||
 | 
					                context, id)
 | 
				
			||||||
 | 
					            super(Ml2PlusPlugin, self).delete_address_scope(context, id)
 | 
				
			||||||
 | 
					            mech_context = driver_context.AddressScopeContext(
 | 
				
			||||||
 | 
					                self, context, address_scope)
 | 
				
			||||||
 | 
					            self.mechanism_manager.delete_address_scope_precommit(mech_context)
 | 
				
			||||||
 | 
					        self.mechanism_manager.delete_address_scope_postcommit(mech_context)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def _ensure_tenant(self, context, resource):
 | 
					    def _ensure_tenant(self, context, resource):
 | 
				
			||||||
        tenant_id = resource['tenant_id']
 | 
					        tenant_id = resource['tenant_id']
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -0,0 +1,176 @@
 | 
				
			|||||||
 | 
					# Copyright (c) 2016 Cisco Systems 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 neutron.api import extensions
 | 
				
			||||||
 | 
					from neutron.api.v2 import attributes
 | 
				
			||||||
 | 
					from neutron.db import address_scope_db as as_db
 | 
				
			||||||
 | 
					from neutron.db import model_base
 | 
				
			||||||
 | 
					from neutron.db import models_v2
 | 
				
			||||||
 | 
					import oslo_db.sqlalchemy.session
 | 
				
			||||||
 | 
					import sqlalchemy as sa
 | 
				
			||||||
 | 
					from sqlalchemy import orm
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from gbpservice.neutron.plugins.ml2plus import driver_api
 | 
				
			||||||
 | 
					from gbpservice.neutron.tests.unit.plugins.ml2plus import (
 | 
				
			||||||
 | 
					    extensions as test_extensions)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class TestExtensionDriverBase(driver_api.ExtensionDriver):
 | 
				
			||||||
 | 
					    _supported_extension_aliases = 'ml2plus_fake_extension'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def initialize(self):
 | 
				
			||||||
 | 
					        # REVISIT(rkukura): Needed?
 | 
				
			||||||
 | 
					        extensions.append_api_extensions_path(test_extensions.__path__)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @property
 | 
				
			||||||
 | 
					    def extension_alias(self):
 | 
				
			||||||
 | 
					        return self._supported_extension_aliases
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class TestExtensionDriver(TestExtensionDriverBase):
 | 
				
			||||||
 | 
					    def initialize(self):
 | 
				
			||||||
 | 
					        super(TestExtensionDriver, self).initialize()
 | 
				
			||||||
 | 
					        self.subnetpool_extension = 'Test_SubnetPool_Extension'
 | 
				
			||||||
 | 
					        self.address_scope_extension = 'Test_AddressScope_Extension'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def _check_create(self, session, data, result):
 | 
				
			||||||
 | 
					        assert(isinstance(session, oslo_db.sqlalchemy.session.Session))
 | 
				
			||||||
 | 
					        assert(isinstance(data, dict))
 | 
				
			||||||
 | 
					        assert('id' not in data)
 | 
				
			||||||
 | 
					        assert(isinstance(result, dict))
 | 
				
			||||||
 | 
					        assert(result['id'] is not None)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def _check_update(self, session, data, result):
 | 
				
			||||||
 | 
					        assert(isinstance(session, oslo_db.sqlalchemy.session.Session))
 | 
				
			||||||
 | 
					        assert(isinstance(data, dict))
 | 
				
			||||||
 | 
					        assert(isinstance(result, dict))
 | 
				
			||||||
 | 
					        assert(result['id'] is not None)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def _check_extend(self, session, result, db_entry,
 | 
				
			||||||
 | 
					                      expected_db_entry_class):
 | 
				
			||||||
 | 
					        assert(isinstance(session, oslo_db.sqlalchemy.session.Session))
 | 
				
			||||||
 | 
					        assert(isinstance(result, dict))
 | 
				
			||||||
 | 
					        assert(result['id'] is not None)
 | 
				
			||||||
 | 
					        assert(isinstance(db_entry, expected_db_entry_class))
 | 
				
			||||||
 | 
					        assert(db_entry.id == result['id'])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def process_create_subnetpool(self, plugin_context, data, result):
 | 
				
			||||||
 | 
					        session = plugin_context.session
 | 
				
			||||||
 | 
					        self._check_create(session, data, result)
 | 
				
			||||||
 | 
					        result['subnetpool_extension'] = self.subnetpool_extension + '_create'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def process_update_subnetpool(self, plugin_context, data, result):
 | 
				
			||||||
 | 
					        session = plugin_context.session
 | 
				
			||||||
 | 
					        self._check_update(session, data, result)
 | 
				
			||||||
 | 
					        self.subnetpool_extension = data['subnetpool_extension']
 | 
				
			||||||
 | 
					        result['subnetpool_extension'] = self.subnetpool_extension + '_update'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def extend_subnetpool_dict(self, session, subnetpool_db, result):
 | 
				
			||||||
 | 
					        self._check_extend(session, result, subnetpool_db,
 | 
				
			||||||
 | 
					                           models_v2.SubnetPool)
 | 
				
			||||||
 | 
					        result['subnetpool_extension'] = self.subnetpool_extension + '_extend'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def process_create_address_scope(self, plugin_context, data, result):
 | 
				
			||||||
 | 
					        session = plugin_context.session
 | 
				
			||||||
 | 
					        self._check_create(session, data, result)
 | 
				
			||||||
 | 
					        result['address_scope_extension'] = (self.address_scope_extension +
 | 
				
			||||||
 | 
					                                             '_create')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def process_update_address_scope(self, plugin_context, data, result):
 | 
				
			||||||
 | 
					        session = plugin_context.session
 | 
				
			||||||
 | 
					        self._check_update(session, data, result)
 | 
				
			||||||
 | 
					        self.address_scope_extension = data['address_scope_extension']
 | 
				
			||||||
 | 
					        result['address_scope_extension'] = (self.address_scope_extension +
 | 
				
			||||||
 | 
					                                             '_update')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def extend_address_scope_dict(self, session, address_scope_db, result):
 | 
				
			||||||
 | 
					        self._check_extend(session, result, address_scope_db,
 | 
				
			||||||
 | 
					                           as_db.AddressScope)
 | 
				
			||||||
 | 
					        result['address_scope_extension'] = (self.address_scope_extension +
 | 
				
			||||||
 | 
					                                             '_extend')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class TestSubnetPoolExtension(model_base.BASEV2):
 | 
				
			||||||
 | 
					    subnetpool_id = sa.Column(sa.String(36),
 | 
				
			||||||
 | 
					                              sa.ForeignKey('subnetpools.id',
 | 
				
			||||||
 | 
					                                            ondelete="CASCADE"),
 | 
				
			||||||
 | 
					                              primary_key=True)
 | 
				
			||||||
 | 
					    value = sa.Column(sa.String(64))
 | 
				
			||||||
 | 
					    subnetpool = orm.relationship(
 | 
				
			||||||
 | 
					        models_v2.SubnetPool,
 | 
				
			||||||
 | 
					        backref=orm.backref('extension', cascade='delete', uselist=False))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class TestAddressScopeExtension(model_base.BASEV2):
 | 
				
			||||||
 | 
					    address_scope_id = sa.Column(sa.String(36),
 | 
				
			||||||
 | 
					                                 sa.ForeignKey('address_scopes.id',
 | 
				
			||||||
 | 
					                                               ondelete="CASCADE"),
 | 
				
			||||||
 | 
					                                 primary_key=True)
 | 
				
			||||||
 | 
					    value = sa.Column(sa.String(64))
 | 
				
			||||||
 | 
					    address_scope = orm.relationship(
 | 
				
			||||||
 | 
					        as_db.AddressScope,
 | 
				
			||||||
 | 
					        backref=orm.backref('extension', cascade='delete', uselist=False))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class TestDBExtensionDriver(TestExtensionDriverBase):
 | 
				
			||||||
 | 
					    def _get_value(self, data, key):
 | 
				
			||||||
 | 
					        value = data[key]
 | 
				
			||||||
 | 
					        if not attributes.is_attr_set(value):
 | 
				
			||||||
 | 
					            value = ''
 | 
				
			||||||
 | 
					        return value
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def process_create_subnetpool(self, plugin_context, data, result):
 | 
				
			||||||
 | 
					        session = plugin_context.session
 | 
				
			||||||
 | 
					        value = self._get_value(data, 'subnetpool_extension')
 | 
				
			||||||
 | 
					        record = TestSubnetPoolExtension(subnetpool_id=result['id'],
 | 
				
			||||||
 | 
					                                         value=value)
 | 
				
			||||||
 | 
					        session.add(record)
 | 
				
			||||||
 | 
					        result['subnetpool_extension'] = value
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def process_update_subnetpool(self, plugin_context, data, result):
 | 
				
			||||||
 | 
					        session = plugin_context.session
 | 
				
			||||||
 | 
					        record = (session.query(TestSubnetPoolExtension).
 | 
				
			||||||
 | 
					                  filter_by(subnetpool_id=result['id']).one())
 | 
				
			||||||
 | 
					        value = data.get('subnetpool_extension')
 | 
				
			||||||
 | 
					        if value and value != record.value:
 | 
				
			||||||
 | 
					            record.value = value
 | 
				
			||||||
 | 
					        result['subnetpool_extension'] = record.value
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def extend_subnetpool_dict(self, session, subnetpool_db, result):
 | 
				
			||||||
 | 
					        value = (subnetpool_db.extension.value
 | 
				
			||||||
 | 
					                 if subnetpool_db.extension else '')
 | 
				
			||||||
 | 
					        result['subnetpool_extension'] = value
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def process_create_address_scope(self, plugin_context, data, result):
 | 
				
			||||||
 | 
					        session = plugin_context.session
 | 
				
			||||||
 | 
					        value = self._get_value(data, 'address_scope_extension')
 | 
				
			||||||
 | 
					        record = TestAddressScopeExtension(address_scope_id=result['id'],
 | 
				
			||||||
 | 
					                                           value=value)
 | 
				
			||||||
 | 
					        session.add(record)
 | 
				
			||||||
 | 
					        result['address_scope_extension'] = value
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def process_update_address_scope(self, plugin_context, data, result):
 | 
				
			||||||
 | 
					        session = plugin_context.session
 | 
				
			||||||
 | 
					        record = (session.query(TestAddressScopeExtension).
 | 
				
			||||||
 | 
					                  filter_by(address_scope_id=result['id']).one())
 | 
				
			||||||
 | 
					        value = data.get('address_scope_extension')
 | 
				
			||||||
 | 
					        if value and value != record.value:
 | 
				
			||||||
 | 
					            record.value = value
 | 
				
			||||||
 | 
					        result['address_scope_extension'] = record.value
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def extend_address_scope_dict(self, session, address_scope_db, result):
 | 
				
			||||||
 | 
					        value = (address_scope_db.extension.value
 | 
				
			||||||
 | 
					                 if address_scope_db.extension else '')
 | 
				
			||||||
 | 
					        result['address_scope_extension'] = value
 | 
				
			||||||
@@ -35,3 +35,65 @@ class LoggerPlusMechanismDriver(driver_api.MechanismDriver,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    def ensure_tenant(self, plugin_context, tenant_id):
 | 
					    def ensure_tenant(self, plugin_context, tenant_id):
 | 
				
			||||||
        LOG.info(_LI("ensure_tenant called with tenant_id %s"), tenant_id)
 | 
					        LOG.info(_LI("ensure_tenant called with tenant_id %s"), tenant_id)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def _log_subnetpool_call(self, method_name, context):
 | 
				
			||||||
 | 
					        LOG.info(_("%(method)s called with subnetpool settings %(current)s "
 | 
				
			||||||
 | 
					                   "(original settings %(original)s)"),
 | 
				
			||||||
 | 
					                 {'method': method_name,
 | 
				
			||||||
 | 
					                  'current': context.current,
 | 
				
			||||||
 | 
					                  'original': context.original})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def create_subnetpool_precommit(self, context):
 | 
				
			||||||
 | 
					        self._log_subnetpool_call("create_subnetpool_precommit",
 | 
				
			||||||
 | 
					                                  context)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def create_subnetpool_postcommit(self, context):
 | 
				
			||||||
 | 
					        self._log_subnetpool_call("create_subnetpool_postcommit",
 | 
				
			||||||
 | 
					                                  context)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def update_subnetpool_precommit(self, context):
 | 
				
			||||||
 | 
					        self._log_subnetpool_call("update_subnetpool_precommit",
 | 
				
			||||||
 | 
					                                  context)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def update_subnetpool_postcommit(self, context):
 | 
				
			||||||
 | 
					        self._log_subnetpool_call("update_subnetpool_postcommit",
 | 
				
			||||||
 | 
					                                  context)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def delete_subnetpool_precommit(self, context):
 | 
				
			||||||
 | 
					        self._log_subnetpool_call("delete_subnetpool_precommit",
 | 
				
			||||||
 | 
					                                  context)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def delete_subnetpool_postcommit(self, context):
 | 
				
			||||||
 | 
					        self._log_subnetpool_call("delete_subnetpool_postcommit",
 | 
				
			||||||
 | 
					                                  context)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def _log_address_scope_call(self, method_name, context):
 | 
				
			||||||
 | 
					        LOG.info(_("%(method)s called with address_scope settings %(current)s "
 | 
				
			||||||
 | 
					                   "(original settings %(original)s)"),
 | 
				
			||||||
 | 
					                 {'method': method_name,
 | 
				
			||||||
 | 
					                  'current': context.current,
 | 
				
			||||||
 | 
					                  'original': context.original})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def create_address_scope_precommit(self, context):
 | 
				
			||||||
 | 
					        self._log_address_scope_call("create_address_scope_precommit",
 | 
				
			||||||
 | 
					                                     context)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def create_address_scope_postcommit(self, context):
 | 
				
			||||||
 | 
					        self._log_address_scope_call("create_address_scope_postcommit",
 | 
				
			||||||
 | 
					                                     context)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def update_address_scope_precommit(self, context):
 | 
				
			||||||
 | 
					        self._log_address_scope_call("update_address_scope_precommit",
 | 
				
			||||||
 | 
					                                     context)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def update_address_scope_postcommit(self, context):
 | 
				
			||||||
 | 
					        self._log_address_scope_call("update_address_scope_postcommit",
 | 
				
			||||||
 | 
					                                     context)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def delete_address_scope_precommit(self, context):
 | 
				
			||||||
 | 
					        self._log_address_scope_call("delete_address_scope_precommit",
 | 
				
			||||||
 | 
					                                     context)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def delete_address_scope_postcommit(self, context):
 | 
				
			||||||
 | 
					        self._log_address_scope_call("delete_address_scope_postcommit",
 | 
				
			||||||
 | 
					                                     context)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -0,0 +1,62 @@
 | 
				
			|||||||
 | 
					# Copyright (c) 2016 Cisco Systems 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 neutron._i18n import _
 | 
				
			||||||
 | 
					from neutron.api import extensions
 | 
				
			||||||
 | 
					from neutron.api.v2 import attributes as attr
 | 
				
			||||||
 | 
					from neutron.extensions import address_scope as as_ext
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					EXTENDED_ATTRIBUTES_2_0 = {
 | 
				
			||||||
 | 
					    attr.SUBNETPOOLS: {
 | 
				
			||||||
 | 
					        'subnetpool_extension': {'allow_post': True,
 | 
				
			||||||
 | 
					                                 'allow_put': True,
 | 
				
			||||||
 | 
					                                 'default': attr.ATTR_NOT_SPECIFIED,
 | 
				
			||||||
 | 
					                                 'is_visible': True,
 | 
				
			||||||
 | 
					                                 'enforce_policy': True},
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    as_ext.ADDRESS_SCOPES: {
 | 
				
			||||||
 | 
					        'address_scope_extension': {'allow_post': True,
 | 
				
			||||||
 | 
					                                    'allow_put': True,
 | 
				
			||||||
 | 
					                                    'default': attr.ATTR_NOT_SPECIFIED,
 | 
				
			||||||
 | 
					                                    'is_visible': True,
 | 
				
			||||||
 | 
					                                    'enforce_policy': True},
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Fake_extension(extensions.ExtensionDescriptor):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @classmethod
 | 
				
			||||||
 | 
					    def get_name(cls):
 | 
				
			||||||
 | 
					        return "ML2Plus fake extension"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @classmethod
 | 
				
			||||||
 | 
					    def get_alias(cls):
 | 
				
			||||||
 | 
					        return "ml2plus_fake_extension"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @classmethod
 | 
				
			||||||
 | 
					    def get_description(cls):
 | 
				
			||||||
 | 
					        return _("Adds test attributes to ML2Plus resources.")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @classmethod
 | 
				
			||||||
 | 
					    def get_updated(cls):
 | 
				
			||||||
 | 
					        return "2016-08-02T10:00:00-00:00"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def get_extended_resources(self, version):
 | 
				
			||||||
 | 
					        if version == "2.0":
 | 
				
			||||||
 | 
					            return EXTENDED_ATTRIBUTES_2_0
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            return {}
 | 
				
			||||||
@@ -0,0 +1,312 @@
 | 
				
			|||||||
 | 
					# Copyright (c) 2016 Cisco Systems 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.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import mock
 | 
				
			||||||
 | 
					import uuid
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from neutron import context
 | 
				
			||||||
 | 
					from neutron import manager
 | 
				
			||||||
 | 
					from neutron.plugins.ml2 import config
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from gbpservice.neutron.tests.unit.plugins.ml2plus.drivers import (
 | 
				
			||||||
 | 
					    extension_test as ext_test)
 | 
				
			||||||
 | 
					from gbpservice.neutron.tests.unit.plugins.ml2plus import test_plugin
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class ExtensionDriverTestCase(test_plugin.Ml2PlusPluginV2TestCase):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    _extension_drivers = ['test_ml2plus']
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def setUp(self):
 | 
				
			||||||
 | 
					        config.cfg.CONF.set_override('extension_drivers',
 | 
				
			||||||
 | 
					                                     self._extension_drivers,
 | 
				
			||||||
 | 
					                                     group='ml2')
 | 
				
			||||||
 | 
					        super(ExtensionDriverTestCase, self).setUp()
 | 
				
			||||||
 | 
					        self._plugin = manager.NeutronManager.get_plugin()
 | 
				
			||||||
 | 
					        self._ctxt = context.get_admin_context()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def _verify_subnetpool_create(self, code, exc_reason):
 | 
				
			||||||
 | 
					        tenant_id = str(uuid.uuid4())
 | 
				
			||||||
 | 
					        data = {'subnetpool': {'prefixes': ['10.0.0.0/8'],
 | 
				
			||||||
 | 
					                               'name': 'sp1',
 | 
				
			||||||
 | 
					                               'tenant_id': tenant_id}}
 | 
				
			||||||
 | 
					        req = self.new_create_request('subnetpools', data)
 | 
				
			||||||
 | 
					        res = req.get_response(self.api)
 | 
				
			||||||
 | 
					        self.assertEqual(code, res.status_int)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        subnetpool = self.deserialize(self.fmt, res)
 | 
				
			||||||
 | 
					        if exc_reason:
 | 
				
			||||||
 | 
					            self.assertEqual(exc_reason,
 | 
				
			||||||
 | 
					                             subnetpool['NeutronError']['type'])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return (subnetpool, tenant_id)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def _verify_subnetpool_update(self, subnetpool, code, exc_reason):
 | 
				
			||||||
 | 
					        sp_id = subnetpool['subnetpool']['id']
 | 
				
			||||||
 | 
					        new_name = 'a_brand_new_name'
 | 
				
			||||||
 | 
					        data = {'subnetpool': {'name': new_name}}
 | 
				
			||||||
 | 
					        req = self.new_update_request('subnetpools', data, sp_id)
 | 
				
			||||||
 | 
					        res = req.get_response(self.api)
 | 
				
			||||||
 | 
					        self.assertEqual(code, res.status_int)
 | 
				
			||||||
 | 
					        error = self.deserialize(self.fmt, res)
 | 
				
			||||||
 | 
					        self.assertEqual(exc_reason,
 | 
				
			||||||
 | 
					                         error['NeutronError']['type'])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_faulty_process_create_subnetpool(self):
 | 
				
			||||||
 | 
					        with mock.patch.object(ext_test.TestExtensionDriver,
 | 
				
			||||||
 | 
					                               'process_create_subnetpool',
 | 
				
			||||||
 | 
					                               side_effect=TypeError):
 | 
				
			||||||
 | 
					            subnetpool, tenant_id = self._verify_subnetpool_create(
 | 
				
			||||||
 | 
					                500, 'HTTPInternalServerError')
 | 
				
			||||||
 | 
					            # Verify the operation is rolled back
 | 
				
			||||||
 | 
					            query_params = "tenant_id=%s" % tenant_id
 | 
				
			||||||
 | 
					            subnetpools = self._list('subnetpools', query_params=query_params)
 | 
				
			||||||
 | 
					            self.assertFalse(subnetpools['subnetpools'])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_faulty_process_update_subnetpool(self):
 | 
				
			||||||
 | 
					        with mock.patch.object(ext_test.TestExtensionDriver,
 | 
				
			||||||
 | 
					                               'process_update_subnetpool',
 | 
				
			||||||
 | 
					                               side_effect=TypeError):
 | 
				
			||||||
 | 
					            subnetpool, tid = self._verify_subnetpool_create(201, None)
 | 
				
			||||||
 | 
					            self._verify_subnetpool_update(subnetpool, 500,
 | 
				
			||||||
 | 
					                                           'HTTPInternalServerError')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_faulty_extend_subnetpool_dict(self):
 | 
				
			||||||
 | 
					        with mock.patch.object(ext_test.TestExtensionDriver,
 | 
				
			||||||
 | 
					                               'extend_subnetpool_dict',
 | 
				
			||||||
 | 
					                               side_effect=[None, None, TypeError]):
 | 
				
			||||||
 | 
					            subnetpool, tid = self._verify_subnetpool_create(201, None)
 | 
				
			||||||
 | 
					            self._verify_subnetpool_update(subnetpool, 400,
 | 
				
			||||||
 | 
					                                           'ExtensionDriverError')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_subnetpool_attr(self):
 | 
				
			||||||
 | 
					        with self.subnetpool(['10.0.0.0/8'], name='sp1',
 | 
				
			||||||
 | 
					                             tenant_id='t1') as subnetpool:
 | 
				
			||||||
 | 
					            # Test create subnetpool
 | 
				
			||||||
 | 
					            ent = subnetpool['subnetpool'].get('subnetpool_extension')
 | 
				
			||||||
 | 
					            self.assertIsNotNone(ent)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            # Test list subnetpools
 | 
				
			||||||
 | 
					            res = self._list('subnetpools')
 | 
				
			||||||
 | 
					            val = res['subnetpools'][0].get('subnetpool_extension')
 | 
				
			||||||
 | 
					            self.assertEqual('Test_SubnetPool_Extension_extend', val)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            # Test subnetpool update
 | 
				
			||||||
 | 
					            data = {'subnetpool':
 | 
				
			||||||
 | 
					                    {'subnetpool_extension':
 | 
				
			||||||
 | 
					                     'Test_SubnetPool_Extension_Update'}}
 | 
				
			||||||
 | 
					            res = self._update('subnetpools', subnetpool['subnetpool']['id'],
 | 
				
			||||||
 | 
					                               data)
 | 
				
			||||||
 | 
					            val = res['subnetpool'].get('subnetpool_extension')
 | 
				
			||||||
 | 
					            self.assertEqual('Test_SubnetPool_Extension_Update_update', val)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_extend_subnetpool_dict(self):
 | 
				
			||||||
 | 
					        with mock.patch.object(
 | 
				
			||||||
 | 
					                ext_test.TestExtensionDriver,
 | 
				
			||||||
 | 
					                'process_update_subnetpool') as pus, mock.patch.object(
 | 
				
			||||||
 | 
					                    ext_test.TestExtensionDriver,
 | 
				
			||||||
 | 
					                    'extend_subnetpool_dict') as esd, self.subnetpool(
 | 
				
			||||||
 | 
					                        ['10.0.0.0/8'], name='sp1',
 | 
				
			||||||
 | 
					                        tenant_id='t1') as subnetpool:
 | 
				
			||||||
 | 
					            subnetpool_id = subnetpool['subnetpool']['id']
 | 
				
			||||||
 | 
					            subnetpool_data = {'subnetpool': {'id': subnetpool_id}}
 | 
				
			||||||
 | 
					            self._plugin.update_subnetpool(self._ctxt, subnetpool_id,
 | 
				
			||||||
 | 
					                                           subnetpool_data)
 | 
				
			||||||
 | 
					            self.assertTrue(pus.called)
 | 
				
			||||||
 | 
					            self.assertTrue(esd.called)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def _verify_address_scope_create(self, code, exc_reason):
 | 
				
			||||||
 | 
					        tenant_id = str(uuid.uuid4())
 | 
				
			||||||
 | 
					        data = {'address_scope': {'ip_version': 4,
 | 
				
			||||||
 | 
					                                  'name': 'as1',
 | 
				
			||||||
 | 
					                                  'tenant_id': tenant_id}}
 | 
				
			||||||
 | 
					        req = self.new_create_request('address-scopes', data)
 | 
				
			||||||
 | 
					        res = req.get_response(self.ext_api)
 | 
				
			||||||
 | 
					        self.assertEqual(code, res.status_int)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        address_scope = self.deserialize(self.fmt, res)
 | 
				
			||||||
 | 
					        if exc_reason:
 | 
				
			||||||
 | 
					            self.assertEqual(exc_reason,
 | 
				
			||||||
 | 
					                             address_scope['NeutronError']['type'])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return (address_scope, tenant_id)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def _verify_address_scope_update(self, address_scope, code, exc_reason):
 | 
				
			||||||
 | 
					        as_id = address_scope['address_scope']['id']
 | 
				
			||||||
 | 
					        new_name = 'a_brand_new_name'
 | 
				
			||||||
 | 
					        data = {'address_scope': {'name': new_name}}
 | 
				
			||||||
 | 
					        req = self.new_update_request('address-scopes', data, as_id)
 | 
				
			||||||
 | 
					        res = req.get_response(self.ext_api)
 | 
				
			||||||
 | 
					        self.assertEqual(code, res.status_int)
 | 
				
			||||||
 | 
					        error = self.deserialize(self.fmt, res)
 | 
				
			||||||
 | 
					        self.assertEqual(exc_reason,
 | 
				
			||||||
 | 
					                         error['NeutronError']['type'])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_faulty_process_create_address_scope(self):
 | 
				
			||||||
 | 
					        with mock.patch.object(ext_test.TestExtensionDriver,
 | 
				
			||||||
 | 
					                               'process_create_address_scope',
 | 
				
			||||||
 | 
					                               side_effect=TypeError):
 | 
				
			||||||
 | 
					            address_scope, tenant_id = self._verify_address_scope_create(
 | 
				
			||||||
 | 
					                500, 'HTTPInternalServerError')
 | 
				
			||||||
 | 
					            # Verify the operation is rolled back
 | 
				
			||||||
 | 
					            query_params = "tenant_id=%s" % tenant_id
 | 
				
			||||||
 | 
					            address_scopes = self._list('address-scopes',
 | 
				
			||||||
 | 
					                                        query_params=query_params)
 | 
				
			||||||
 | 
					            self.assertFalse(address_scopes['address_scopes'])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_faulty_process_update_address_scope(self):
 | 
				
			||||||
 | 
					        with mock.patch.object(ext_test.TestExtensionDriver,
 | 
				
			||||||
 | 
					                               'process_update_address_scope',
 | 
				
			||||||
 | 
					                               side_effect=TypeError):
 | 
				
			||||||
 | 
					            address_scope, tid = self._verify_address_scope_create(201, None)
 | 
				
			||||||
 | 
					            self._verify_address_scope_update(address_scope, 500,
 | 
				
			||||||
 | 
					                                              'HTTPInternalServerError')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_faulty_extend_address_scope_dict(self):
 | 
				
			||||||
 | 
					        with mock.patch.object(ext_test.TestExtensionDriver,
 | 
				
			||||||
 | 
					                               'extend_address_scope_dict',
 | 
				
			||||||
 | 
					                               side_effect=[None, None, TypeError]):
 | 
				
			||||||
 | 
					            address_scope, tid = self._verify_address_scope_create(201, None)
 | 
				
			||||||
 | 
					            self._verify_address_scope_update(address_scope, 400,
 | 
				
			||||||
 | 
					                                              'ExtensionDriverError')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_address_scope_attr(self):
 | 
				
			||||||
 | 
					        with self.address_scope(4, name='as1',
 | 
				
			||||||
 | 
					                                tenant_id='t1') as address_scope:
 | 
				
			||||||
 | 
					            # Test create address_scope
 | 
				
			||||||
 | 
					            ent = address_scope['address_scope'].get('address_scope_extension')
 | 
				
			||||||
 | 
					            self.assertIsNotNone(ent)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            # Test list address_scopes
 | 
				
			||||||
 | 
					            res = self._list('address-scopes')
 | 
				
			||||||
 | 
					            val = res['address_scopes'][0].get('address_scope_extension')
 | 
				
			||||||
 | 
					            self.assertEqual('Test_AddressScope_Extension_extend', val)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            # Test address_scope update
 | 
				
			||||||
 | 
					            data = {'address_scope':
 | 
				
			||||||
 | 
					                    {'address_scope_extension':
 | 
				
			||||||
 | 
					                     'Test_AddressScope_Extension_Update'}}
 | 
				
			||||||
 | 
					            res = self._update('address-scopes',
 | 
				
			||||||
 | 
					                               address_scope['address_scope']['id'], data)
 | 
				
			||||||
 | 
					            val = res['address_scope'].get('address_scope_extension')
 | 
				
			||||||
 | 
					            self.assertEqual('Test_AddressScope_Extension_Update_update', val)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_extend_address_scope_dict(self):
 | 
				
			||||||
 | 
					        with mock.patch.object(
 | 
				
			||||||
 | 
					                ext_test.TestExtensionDriver,
 | 
				
			||||||
 | 
					                'process_update_address_scope') as puas, mock.patch.object(
 | 
				
			||||||
 | 
					                    ext_test.TestExtensionDriver,
 | 
				
			||||||
 | 
					                    'extend_address_scope_dict') as easd, self.address_scope(
 | 
				
			||||||
 | 
					                        4, name='as1', tenant_id='t1') as address_scope:
 | 
				
			||||||
 | 
					            address_scope_id = address_scope['address_scope']['id']
 | 
				
			||||||
 | 
					            address_scope_data = {'address_scope': {'id': address_scope_id}}
 | 
				
			||||||
 | 
					            self._plugin.update_address_scope(self._ctxt, address_scope_id,
 | 
				
			||||||
 | 
					                                              address_scope_data)
 | 
				
			||||||
 | 
					            self.assertTrue(puas.called)
 | 
				
			||||||
 | 
					            self.assertTrue(easd.called)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class DBExtensionDriverTestCase(test_plugin.Ml2PlusPluginV2TestCase):
 | 
				
			||||||
 | 
					    _extension_drivers = ['testdb_ml2plus']
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def setUp(self):
 | 
				
			||||||
 | 
					        config.cfg.CONF.set_override('extension_drivers',
 | 
				
			||||||
 | 
					                                     self._extension_drivers,
 | 
				
			||||||
 | 
					                                     group='ml2')
 | 
				
			||||||
 | 
					        super(DBExtensionDriverTestCase, self).setUp()
 | 
				
			||||||
 | 
					        self._plugin = manager.NeutronManager.get_plugin()
 | 
				
			||||||
 | 
					        self._ctxt = context.get_admin_context()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_subnetpool_attr(self):
 | 
				
			||||||
 | 
					        with self.subnetpool(['10.0.0.0/8'], name='sp1',
 | 
				
			||||||
 | 
					                             tenant_id='t1') as subnetpool:
 | 
				
			||||||
 | 
					            # Test create with default value.
 | 
				
			||||||
 | 
					            sp_id = subnetpool['subnetpool']['id']
 | 
				
			||||||
 | 
					            val = subnetpool['subnetpool']['subnetpool_extension']
 | 
				
			||||||
 | 
					            self.assertEqual("", val)
 | 
				
			||||||
 | 
					            res = self._show('subnetpools', sp_id)
 | 
				
			||||||
 | 
					            val = res['subnetpool']['subnetpool_extension']
 | 
				
			||||||
 | 
					            self.assertEqual("", val)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            # Test list.
 | 
				
			||||||
 | 
					            res = self._list('subnetpools')
 | 
				
			||||||
 | 
					            val = res['subnetpools'][0]['subnetpool_extension']
 | 
				
			||||||
 | 
					            self.assertEqual("", val)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # Test create with explicit value.
 | 
				
			||||||
 | 
					        data = {'subnetpool':
 | 
				
			||||||
 | 
					                {'prefixes': ['10.0.0.0/8'],
 | 
				
			||||||
 | 
					                 'name': 'sp2',
 | 
				
			||||||
 | 
					                 'tenant_id': 't1',
 | 
				
			||||||
 | 
					                 'subnetpool_extension': 'abc'}}
 | 
				
			||||||
 | 
					        req = self.new_create_request('subnetpools', data, self.fmt)
 | 
				
			||||||
 | 
					        res = req.get_response(self.api)
 | 
				
			||||||
 | 
					        subnetpool = self.deserialize(self.fmt, res)
 | 
				
			||||||
 | 
					        subnetpool_id = subnetpool['subnetpool']['id']
 | 
				
			||||||
 | 
					        val = subnetpool['subnetpool']['subnetpool_extension']
 | 
				
			||||||
 | 
					        self.assertEqual("abc", val)
 | 
				
			||||||
 | 
					        res = self._show('subnetpools', subnetpool_id)
 | 
				
			||||||
 | 
					        val = res['subnetpool']['subnetpool_extension']
 | 
				
			||||||
 | 
					        self.assertEqual("abc", val)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # Test update.
 | 
				
			||||||
 | 
					        data = {'subnetpool': {'subnetpool_extension': "def"}}
 | 
				
			||||||
 | 
					        res = self._update('subnetpools', subnetpool_id, data)
 | 
				
			||||||
 | 
					        val = res['subnetpool']['subnetpool_extension']
 | 
				
			||||||
 | 
					        self.assertEqual("def", val)
 | 
				
			||||||
 | 
					        res = self._show('subnetpools', subnetpool_id)
 | 
				
			||||||
 | 
					        val = res['subnetpool']['subnetpool_extension']
 | 
				
			||||||
 | 
					        self.assertEqual("def", val)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_address_scope_attr(self):
 | 
				
			||||||
 | 
					        with self.address_scope(4, name='as1',
 | 
				
			||||||
 | 
					                                tenant_id='t1') as address_scope:
 | 
				
			||||||
 | 
					            # Test create with default value.
 | 
				
			||||||
 | 
					            as_id = address_scope['address_scope']['id']
 | 
				
			||||||
 | 
					            val = address_scope['address_scope']['address_scope_extension']
 | 
				
			||||||
 | 
					            self.assertEqual("", val)
 | 
				
			||||||
 | 
					            res = self._show('address-scopes', as_id)
 | 
				
			||||||
 | 
					            val = res['address_scope']['address_scope_extension']
 | 
				
			||||||
 | 
					            self.assertEqual("", val)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            # Test list.
 | 
				
			||||||
 | 
					            res = self._list('address-scopes')
 | 
				
			||||||
 | 
					            val = res['address_scopes'][0]['address_scope_extension']
 | 
				
			||||||
 | 
					            self.assertEqual("", val)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # Test create with explicit value.
 | 
				
			||||||
 | 
					        data = {'address_scope':
 | 
				
			||||||
 | 
					                {'ip_version': 4,
 | 
				
			||||||
 | 
					                 'name': 'as2',
 | 
				
			||||||
 | 
					                 'tenant_id': 't1',
 | 
				
			||||||
 | 
					                 'address_scope_extension': 'abc'}}
 | 
				
			||||||
 | 
					        req = self.new_create_request('address-scopes', data, self.fmt)
 | 
				
			||||||
 | 
					        res = req.get_response(self.ext_api)
 | 
				
			||||||
 | 
					        address_scope = self.deserialize(self.fmt, res)
 | 
				
			||||||
 | 
					        address_scope_id = address_scope['address_scope']['id']
 | 
				
			||||||
 | 
					        val = address_scope['address_scope']['address_scope_extension']
 | 
				
			||||||
 | 
					        self.assertEqual("abc", val)
 | 
				
			||||||
 | 
					        res = self._show('address-scopes', address_scope_id)
 | 
				
			||||||
 | 
					        val = res['address_scope']['address_scope_extension']
 | 
				
			||||||
 | 
					        self.assertEqual("abc", val)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # Test update.
 | 
				
			||||||
 | 
					        data = {'address_scope': {'address_scope_extension': "def"}}
 | 
				
			||||||
 | 
					        res = self._update('address-scopes', address_scope_id, data)
 | 
				
			||||||
 | 
					        val = res['address_scope']['address_scope_extension']
 | 
				
			||||||
 | 
					        self.assertEqual("def", val)
 | 
				
			||||||
 | 
					        res = self._show('address-scopes', address_scope_id)
 | 
				
			||||||
 | 
					        val = res['address_scope']['address_scope_extension']
 | 
				
			||||||
 | 
					        self.assertEqual("def", val)
 | 
				
			||||||
@@ -15,9 +15,12 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import mock
 | 
					import mock
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from neutron.api import extensions
 | 
				
			||||||
from neutron import manager
 | 
					from neutron import manager
 | 
				
			||||||
from neutron.plugins.ml2 import config
 | 
					from neutron.plugins.ml2 import config
 | 
				
			||||||
 | 
					from neutron.tests.unit.api import test_extensions
 | 
				
			||||||
from neutron.tests.unit.db import test_db_base_plugin_v2 as test_plugin
 | 
					from neutron.tests.unit.db import test_db_base_plugin_v2 as test_plugin
 | 
				
			||||||
 | 
					from neutron.tests.unit.extensions import test_address_scope
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from gbpservice.neutron.tests.unit.plugins.ml2plus.drivers import (
 | 
					from gbpservice.neutron.tests.unit.plugins.ml2plus.drivers import (
 | 
				
			||||||
    mechanism_logger as mech_logger)
 | 
					    mechanism_logger as mech_logger)
 | 
				
			||||||
@@ -28,7 +31,7 @@ PLUGIN_NAME = 'gbpservice.neutron.plugins.ml2plus.plugin.Ml2PlusPlugin'
 | 
				
			|||||||
# This is just a quick sanity test that basic ML2 plugin functionality
 | 
					# This is just a quick sanity test that basic ML2 plugin functionality
 | 
				
			||||||
# is preserved.
 | 
					# is preserved.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class Ml2PlusPluginV2TestCase(test_plugin.NeutronDbPluginV2TestCase):
 | 
					class Ml2PlusPluginV2TestCase(test_address_scope.AddressScopeTestCase):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def setUp(self):
 | 
					    def setUp(self):
 | 
				
			||||||
        # Enable the test mechanism driver to ensure that
 | 
					        # Enable the test mechanism driver to ensure that
 | 
				
			||||||
@@ -41,6 +44,8 @@ class Ml2PlusPluginV2TestCase(test_plugin.NeutronDbPluginV2TestCase):
 | 
				
			|||||||
                                     ['physnet1:1000:1099'],
 | 
					                                     ['physnet1:1000:1099'],
 | 
				
			||||||
                                     group='ml2_type_vlan')
 | 
					                                     group='ml2_type_vlan')
 | 
				
			||||||
        super(Ml2PlusPluginV2TestCase, self).setUp(PLUGIN_NAME)
 | 
					        super(Ml2PlusPluginV2TestCase, self).setUp(PLUGIN_NAME)
 | 
				
			||||||
 | 
					        ext_mgr = extensions.PluginAwareExtensionManager.get_instance()
 | 
				
			||||||
 | 
					        self.ext_api = test_extensions.setup_extensions_middleware(ext_mgr)
 | 
				
			||||||
        self.port_create_status = 'DOWN'
 | 
					        self.port_create_status = 'DOWN'
 | 
				
			||||||
        self.plugin = manager.NeutronManager.get_plugin()
 | 
					        self.plugin = manager.NeutronManager.get_plugin()
 | 
				
			||||||
        self.plugin.start_rpc_listeners()
 | 
					        self.plugin.start_rpc_listeners()
 | 
				
			||||||
@@ -136,6 +141,145 @@ class TestEnsureTenant(Ml2PlusPluginV2TestCase):
 | 
				
			|||||||
                                any_order=True)
 | 
					                                any_order=True)
 | 
				
			||||||
            self.assertEqual(2, et.call_count)
 | 
					            self.assertEqual(2, et.call_count)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_subnetpool(self):
 | 
				
			||||||
 | 
					        with mock.patch.object(mech_logger.LoggerPlusMechanismDriver,
 | 
				
			||||||
 | 
					                               'ensure_tenant') as et:
 | 
				
			||||||
 | 
					            self._make_subnetpool(self.fmt, ['10.0.0.0/8'], name='sp1',
 | 
				
			||||||
 | 
					                                  tenant_id='t1')
 | 
				
			||||||
 | 
					            et.assert_called_once_with(mock.ANY, 't1')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_address_scope(self):
 | 
				
			||||||
 | 
					        with mock.patch.object(mech_logger.LoggerPlusMechanismDriver,
 | 
				
			||||||
 | 
					                               'ensure_tenant') as et:
 | 
				
			||||||
 | 
					            self._make_address_scope(self.fmt, 4, name='as1', tenant_id='t1')
 | 
				
			||||||
 | 
					            et.assert_called_once_with(mock.ANY, 't1')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class TestSubnetPool(Ml2PlusPluginV2TestCase):
 | 
				
			||||||
 | 
					    def test_create(self):
 | 
				
			||||||
 | 
					        with mock.patch.object(mech_logger.LoggerPlusMechanismDriver,
 | 
				
			||||||
 | 
					                               'create_subnetpool_precommit') as pre:
 | 
				
			||||||
 | 
					            with mock.patch.object(mech_logger.LoggerPlusMechanismDriver,
 | 
				
			||||||
 | 
					                                   'create_subnetpool_postcommit') as post:
 | 
				
			||||||
 | 
					                self._make_subnetpool(self.fmt, ['10.0.0.0/8'], name='sp1',
 | 
				
			||||||
 | 
					                                      tenant_id='t1')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                self.assertEqual(1, pre.call_count)
 | 
				
			||||||
 | 
					                self.assertEqual('sp1',
 | 
				
			||||||
 | 
					                                 pre.call_args[0][0].current['name'])
 | 
				
			||||||
 | 
					                self.assertIsNone(pre.call_args[0][0].original)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                self.assertEqual(1, post.call_count)
 | 
				
			||||||
 | 
					                self.assertEqual('sp1',
 | 
				
			||||||
 | 
					                                 post.call_args[0][0].current['name'])
 | 
				
			||||||
 | 
					                self.assertIsNone(post.call_args[0][0].original)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_update(self):
 | 
				
			||||||
 | 
					        subnetpool = self._make_subnetpool(
 | 
				
			||||||
 | 
					            self.fmt, ['10.0.0.0/8'], name='sp1', tenant_id='t1')['subnetpool']
 | 
				
			||||||
 | 
					        data = {'subnetpool': {'name': 'newnameforsubnetpool'}}
 | 
				
			||||||
 | 
					        with mock.patch.object(mech_logger.LoggerPlusMechanismDriver,
 | 
				
			||||||
 | 
					                               'update_subnetpool_precommit') as pre:
 | 
				
			||||||
 | 
					            with mock.patch.object(mech_logger.LoggerPlusMechanismDriver,
 | 
				
			||||||
 | 
					                                   'update_subnetpool_postcommit') as post:
 | 
				
			||||||
 | 
					                res = self._update('subnetpools', subnetpool['id'],
 | 
				
			||||||
 | 
					                                   data)['subnetpool']
 | 
				
			||||||
 | 
					                self.assertEqual('newnameforsubnetpool', res['name'])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                self.assertEqual(1, pre.call_count)
 | 
				
			||||||
 | 
					                self.assertEqual('newnameforsubnetpool',
 | 
				
			||||||
 | 
					                                 pre.call_args[0][0].current['name'])
 | 
				
			||||||
 | 
					                self.assertEqual('sp1',
 | 
				
			||||||
 | 
					                                 pre.call_args[0][0].original['name'])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                self.assertEqual(1, post.call_count)
 | 
				
			||||||
 | 
					                self.assertEqual('newnameforsubnetpool',
 | 
				
			||||||
 | 
					                                 post.call_args[0][0].current['name'])
 | 
				
			||||||
 | 
					                self.assertEqual('sp1',
 | 
				
			||||||
 | 
					                                 post.call_args[0][0].original['name'])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_delete(self):
 | 
				
			||||||
 | 
					        subnetpool = self._make_subnetpool(
 | 
				
			||||||
 | 
					            self.fmt, ['10.0.0.0/8'], name='sp1', tenant_id='t1')['subnetpool']
 | 
				
			||||||
 | 
					        with mock.patch.object(mech_logger.LoggerPlusMechanismDriver,
 | 
				
			||||||
 | 
					                               'delete_subnetpool_precommit') as pre:
 | 
				
			||||||
 | 
					            with mock.patch.object(mech_logger.LoggerPlusMechanismDriver,
 | 
				
			||||||
 | 
					                                   'delete_subnetpool_postcommit') as post:
 | 
				
			||||||
 | 
					                self._delete('subnetpools', subnetpool['id'])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                self.assertEqual(1, pre.call_count)
 | 
				
			||||||
 | 
					                self.assertEqual('sp1',
 | 
				
			||||||
 | 
					                                 pre.call_args[0][0].current['name'])
 | 
				
			||||||
 | 
					                self.assertIsNone(pre.call_args[0][0].original)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                self.assertEqual(1, post.call_count)
 | 
				
			||||||
 | 
					                self.assertEqual('sp1',
 | 
				
			||||||
 | 
					                                 post.call_args[0][0].current['name'])
 | 
				
			||||||
 | 
					                self.assertIsNone(post.call_args[0][0].original)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class TestAddressScope(Ml2PlusPluginV2TestCase):
 | 
				
			||||||
 | 
					    def test_create(self):
 | 
				
			||||||
 | 
					        with mock.patch.object(mech_logger.LoggerPlusMechanismDriver,
 | 
				
			||||||
 | 
					                               'create_address_scope_precommit') as pre:
 | 
				
			||||||
 | 
					            with mock.patch.object(mech_logger.LoggerPlusMechanismDriver,
 | 
				
			||||||
 | 
					                                   'create_address_scope_postcommit') as post:
 | 
				
			||||||
 | 
					                self._make_address_scope(self.fmt, 4, name='as1',
 | 
				
			||||||
 | 
					                                         tenant_id='t1')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                self.assertEqual(1, pre.call_count)
 | 
				
			||||||
 | 
					                self.assertEqual('as1',
 | 
				
			||||||
 | 
					                                 pre.call_args[0][0].current['name'])
 | 
				
			||||||
 | 
					                self.assertIsNone(pre.call_args[0][0].original)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                self.assertEqual(1, post.call_count)
 | 
				
			||||||
 | 
					                self.assertEqual('as1',
 | 
				
			||||||
 | 
					                                 post.call_args[0][0].current['name'])
 | 
				
			||||||
 | 
					                self.assertIsNone(post.call_args[0][0].original)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_update(self):
 | 
				
			||||||
 | 
					        address_scope = self._make_address_scope(
 | 
				
			||||||
 | 
					            self.fmt, 4, name='as1', tenant_id='t1')['address_scope']
 | 
				
			||||||
 | 
					        data = {'address_scope': {'name': 'newnameforaddress_scope'}}
 | 
				
			||||||
 | 
					        with mock.patch.object(mech_logger.LoggerPlusMechanismDriver,
 | 
				
			||||||
 | 
					                               'update_address_scope_precommit') as pre:
 | 
				
			||||||
 | 
					            with mock.patch.object(mech_logger.LoggerPlusMechanismDriver,
 | 
				
			||||||
 | 
					                                   'update_address_scope_postcommit') as post:
 | 
				
			||||||
 | 
					                res = self._update('address-scopes', address_scope['id'],
 | 
				
			||||||
 | 
					                                   data)['address_scope']
 | 
				
			||||||
 | 
					                self.assertEqual('newnameforaddress_scope', res['name'])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                self.assertEqual(1, pre.call_count)
 | 
				
			||||||
 | 
					                self.assertEqual('newnameforaddress_scope',
 | 
				
			||||||
 | 
					                                 pre.call_args[0][0].current['name'])
 | 
				
			||||||
 | 
					                self.assertEqual('as1',
 | 
				
			||||||
 | 
					                                 pre.call_args[0][0].original['name'])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                self.assertEqual(1, post.call_count)
 | 
				
			||||||
 | 
					                self.assertEqual('newnameforaddress_scope',
 | 
				
			||||||
 | 
					                                 post.call_args[0][0].current['name'])
 | 
				
			||||||
 | 
					                self.assertEqual('as1',
 | 
				
			||||||
 | 
					                                 post.call_args[0][0].original['name'])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_delete(self):
 | 
				
			||||||
 | 
					        address_scope = self._make_address_scope(
 | 
				
			||||||
 | 
					            self.fmt, 4, name='as1', tenant_id='t1')['address_scope']
 | 
				
			||||||
 | 
					        with mock.patch.object(mech_logger.LoggerPlusMechanismDriver,
 | 
				
			||||||
 | 
					                               'delete_address_scope_precommit') as pre:
 | 
				
			||||||
 | 
					            with mock.patch.object(mech_logger.LoggerPlusMechanismDriver,
 | 
				
			||||||
 | 
					                                   'delete_address_scope_postcommit') as post:
 | 
				
			||||||
 | 
					                self._delete('address-scopes', address_scope['id'])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                self.assertEqual(1, pre.call_count)
 | 
				
			||||||
 | 
					                self.assertEqual('as1',
 | 
				
			||||||
 | 
					                                 pre.call_args[0][0].current['name'])
 | 
				
			||||||
 | 
					                self.assertIsNone(pre.call_args[0][0].original)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                self.assertEqual(1, post.call_count)
 | 
				
			||||||
 | 
					                self.assertEqual('as1',
 | 
				
			||||||
 | 
					                                 post.call_args[0][0].current['name'])
 | 
				
			||||||
 | 
					                self.assertIsNone(post.call_args[0][0].original)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class TestMl2BasicGet(test_plugin.TestBasicGet,
 | 
					class TestMl2BasicGet(test_plugin.TestBasicGet,
 | 
				
			||||||
                      Ml2PlusPluginV2TestCase):
 | 
					                      Ml2PlusPluginV2TestCase):
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -78,6 +78,8 @@ neutron.ml2.mechanism_drivers =
 | 
				
			|||||||
    stitching_gbp = gbpservice.neutron.plugins.ml2.drivers.grouppolicy.stitching.driver:TrafficStitchingMechanismGBPDriver
 | 
					    stitching_gbp = gbpservice.neutron.plugins.ml2.drivers.grouppolicy.stitching.driver:TrafficStitchingMechanismGBPDriver
 | 
				
			||||||
neutron.ml2.extension_drivers =
 | 
					neutron.ml2.extension_drivers =
 | 
				
			||||||
    apic_aim = gbpservice.neutron.plugins.ml2plus.drivers.apic_aim.extension_driver:ApicExtensionDriver
 | 
					    apic_aim = gbpservice.neutron.plugins.ml2plus.drivers.apic_aim.extension_driver:ApicExtensionDriver
 | 
				
			||||||
 | 
					    test_ml2plus = gbpservice.neutron.tests.unit.plugins.ml2plus.drivers.extension_test:TestExtensionDriver
 | 
				
			||||||
 | 
					    testdb_ml2plus = gbpservice.neutron.tests.unit.plugins.ml2plus.drivers.extension_test:TestDBExtensionDriver
 | 
				
			||||||
gbpservice.neutron.servicechain.servicechain_drivers =
 | 
					gbpservice.neutron.servicechain.servicechain_drivers =
 | 
				
			||||||
    dummy = gbpservice.neutron.services.servicechain.plugins.msc.drivers.dummy_driver:NoopDriver
 | 
					    dummy = gbpservice.neutron.services.servicechain.plugins.msc.drivers.dummy_driver:NoopDriver
 | 
				
			||||||
    simplechain_driver = gbpservice.neutron.services.servicechain.plugins.msc.drivers.simplechain_driver:SimpleChainDriver
 | 
					    simplechain_driver = gbpservice.neutron.services.servicechain.plugins.msc.drivers.simplechain_driver:SimpleChainDriver
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user