]> review.fuel-infra Code Review - openstack-build/neutron-build.git/commitdiff
Segregate the VSM calls from database calls in N1kv plugin
authorAbhishek Raut <abhraut@cisco.com>
Fri, 21 Mar 2014 09:26:10 +0000 (02:26 -0700)
committerAbhishek Raut <abhraut@cisco.com>
Fri, 25 Apr 2014 00:24:06 +0000 (17:24 -0700)
Rearrange the code in such a way that the calls to the VSM are
outside the database session. This avoids DB locks on n1kv tables.

Change-Id: Ic0f0d816cca06a3b03fdd9b58ee7599ddf65473e
Closes-Bug: 1290646

neutron/plugins/cisco/n1kv/n1kv_neutron_plugin.py

index cad737842385deb52e8a91e5fa8ac28d54bb0e13..62fa75349e776c43d9a71e557b76f5eafb1ec199 100644 (file)
@@ -846,45 +846,34 @@ class N1kvNeutronPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
         n1kvclient.update_network_segment(subnet['network_id'], body=body)
         n1kvclient.delete_ip_pool(subnet['id'])
 
-    def _send_create_port_request(self, context, port):
+    def _send_create_port_request(self,
+                                  context,
+                                  port,
+                                  port_count,
+                                  policy_profile,
+                                  vm_network_name):
         """
         Send create port request to VSM.
 
         Create a VM network for a network and policy profile combination.
         If the VM network already exists, bind this port to the existing
-        VM network and increment its port count.
+        VM network on the VSM.
         :param context: neutron api request context
         :param port: port dictionary
+        :param port_count: integer representing the number of ports in one
+                           VM Network
+        :param policy_profile: object of type policy profile
+        :param vm_network_name: string representing the name of the VM
+                                network
         """
         LOG.debug(_('_send_create_port_request: %s'), port)
-        try:
-            vm_network = n1kv_db_v2.get_vm_network(
-                context.session,
-                port[n1kv.PROFILE_ID],
-                port['network_id'])
-        except cisco_exceptions.VMNetworkNotFound:
-            policy_profile = n1kv_db_v2.get_policy_profile(
-                context.session, port[n1kv.PROFILE_ID])
-            vm_network_name = (c_const.VM_NETWORK_NAME_PREFIX +
-                               str(port[n1kv.PROFILE_ID]) +
-                               "_" + str(port['network_id']))
-            port_count = 1
-            n1kv_db_v2.add_vm_network(context.session,
-                                      vm_network_name,
-                                      port[n1kv.PROFILE_ID],
-                                      port['network_id'],
-                                      port_count)
-            n1kvclient = n1kv_client.Client()
+        n1kvclient = n1kv_client.Client()
+        if port_count == 1:
             n1kvclient.create_vm_network(port,
                                          vm_network_name,
                                          policy_profile)
         else:
-            vm_network_name = vm_network['name']
-            n1kvclient = n1kv_client.Client()
             n1kvclient.create_n1kv_port(port, vm_network_name)
-            vm_network['port_count'] += 1
-            n1kv_db_v2.update_vm_network_port_count(
-                context.session, vm_network_name, vm_network['port_count'])
 
     def _send_update_port_request(self, port_id, mac_address, vm_network_name):
         """
@@ -900,29 +889,20 @@ class N1kvNeutronPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
         n1kvclient = n1kv_client.Client()
         n1kvclient.update_n1kv_port(vm_network_name, port_id, body)
 
-    def _send_delete_port_request(self, context, id):
+    def _send_delete_port_request(self, context, port, vm_network):
         """
         Send delete port request to VSM.
 
-        Decrement the port count of the VM network after deleting the port.
-        If the port count reaches zero, delete the VM network.
+        Delete the port on the VSM. If it is the last port on the VM Network,
+        delete the VM Network.
         :param context: neutron api request context
-        :param id: UUID of the port to be deleted
-        """
-        LOG.debug(_('_send_delete_port_request: %s'), id)
-        port = self.get_port(context, id)
-        vm_network = n1kv_db_v2.get_vm_network(context.session,
-                                               port[n1kv.PROFILE_ID],
-                                               port['network_id'])
-        vm_network['port_count'] -= 1
-        n1kv_db_v2.update_vm_network_port_count(
-            context.session, vm_network['name'], vm_network['port_count'])
+        :param port: port object which is to be deleted
+        :param vm_network: VM network object with which the port is associated
+        """
+        LOG.debug(_('_send_delete_port_request: %s'), port['id'])
         n1kvclient = n1kv_client.Client()
-        n1kvclient.delete_n1kv_port(vm_network['name'], id)
+        n1kvclient.delete_n1kv_port(vm_network['name'], port['id'])
         if vm_network['port_count'] == 0:
-            n1kv_db_v2.delete_vm_network(context.session,
-                                         port[n1kv.PROFILE_ID],
-                                         port['network_id'])
             n1kvclient.delete_vm_network(vm_network['name'])
 
     def _get_segmentation_id(self, context, id):
@@ -1010,19 +990,16 @@ class N1kvNeutronPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
             self._process_l3_create(context, net, network['network'])
             self._extend_network_dict_provider(context, net)
             self._extend_network_dict_profile(context, net)
-
         try:
             if network_type == c_const.NETWORK_TYPE_MULTI_SEGMENT:
                 self._send_add_multi_segment_request(context, net['id'],
                                                      segment_pairs)
             else:
                 self._send_create_network_request(context, net, segment_pairs)
-                # note - exception will rollback entire transaction
         except(cisco_exceptions.VSMError,
                cisco_exceptions.VSMConnectionFailed):
             super(N1kvNeutronPluginV2, self).delete_network(context, net['id'])
         else:
-            # note - exception will rollback entire transaction
             LOG.debug(_("Created network: %s"), net['id'])
             return net
 
@@ -1108,13 +1085,12 @@ class N1kvNeutronPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
             elif binding.network_type == c_const.NETWORK_TYPE_VLAN:
                 n1kv_db_v2.release_vlan(session, binding.physical_network,
                                         binding.segmentation_id)
-            # the network_binding record is deleted via cascade from
-            # the network record, so explicit removal is not necessary
-            self._send_delete_network_request(context, network)
-
             self._process_l3_delete(context, id)
             super(N1kvNeutronPluginV2, self).delete_network(context, id)
-            LOG.debug(_("Deleted network: %s"), id)
+            # the network_binding record is deleted via cascade from
+            # the network record, so explicit removal is not necessary
+        self._send_delete_network_request(context, network)
+        LOG.debug(_("Deleted network: %s"), id)
 
     def get_network(self, context, id, fields=None):
         """
@@ -1167,6 +1143,12 @@ class N1kvNeutronPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
         :param port: port dictionary
         :returns: port object
         """
+        p_profile = None
+        port_count = None
+        vm_network_name = None
+        profile_id_set = False
+
+        # Set the network policy profile id for auto generated L3/DHCP ports
         if ('device_id' in port['port'] and port['port']['device_owner'] in
             [constants.DEVICE_OWNER_DHCP, constants.DEVICE_OWNER_ROUTER_INTF,
              constants.DEVICE_OWNER_ROUTER_GW,
@@ -1176,11 +1158,11 @@ class N1kvNeutronPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
             if p_profile:
                 port['port']['n1kv:profile_id'] = p_profile['id']
 
-        profile_id_set = False
         if n1kv.PROFILE_ID in port['port']:
             profile_id = port['port'].get(n1kv.PROFILE_ID)
             profile_id_set = attributes.is_attr_set(profile_id)
 
+        # Set the default policy profile id for ports if no id is set
         if not profile_id_set:
             p_profile_name = c_conf.CISCO_N1K.default_policy_profile
             p_profile = self._get_policy_profile_by_name(p_profile_name)
@@ -1188,27 +1170,56 @@ class N1kvNeutronPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
                 port['port']['n1kv:profile_id'] = p_profile['id']
                 profile_id_set = True
 
-        if profile_id_set:
-            profile_id = self._process_policy_profile(context,
-                                                      port['port'])
-            LOG.debug(_('Create port: profile_id=%s'), profile_id)
-            session = context.session
-            with session.begin(subtransactions=True):
-                pt = super(N1kvNeutronPluginV2, self).create_port(context,
-                                                                  port)
-                n1kv_db_v2.add_port_binding(session, pt['id'], profile_id)
-                self._extend_port_dict_profile(context, pt)
-                self._process_portbindings_create_and_update(context,
-                                                             port['port'],
-                                                             pt)
+        profile_id = self._process_policy_profile(context,
+                                                  port['port'])
+        LOG.debug(_('Create port: profile_id=%s'), profile_id)
+        session = context.session
+        with session.begin(subtransactions=True):
+            pt = super(N1kvNeutronPluginV2, self).create_port(context,
+                                                              port)
+            n1kv_db_v2.add_port_binding(session, pt['id'], profile_id)
+            self._extend_port_dict_profile(context, pt)
             try:
-                self._send_create_port_request(context, pt)
-            except(cisco_exceptions.VSMError,
-                   cisco_exceptions.VSMConnectionFailed):
-                super(N1kvNeutronPluginV2, self).delete_port(context, pt['id'])
+                vm_network = n1kv_db_v2.get_vm_network(
+                    context.session,
+                    profile_id,
+                    pt['network_id'])
+            except cisco_exceptions.VMNetworkNotFound:
+                # Create a VM Network if no VM network exists.
+                vm_network_name = "%s%s_%s" % (c_const.VM_NETWORK_NAME_PREFIX,
+                                               profile_id,
+                                               pt['network_id'])
+                port_count = 1
+                n1kv_db_v2.add_vm_network(context.session,
+                                          vm_network_name,
+                                          profile_id,
+                                          pt['network_id'],
+                                          port_count)
             else:
-                LOG.debug(_("Created port: %s"), pt)
-                return pt
+                # Update port count of the VM network.
+                vm_network_name = vm_network['name']
+                port_count = vm_network['port_count'] + 1
+                n1kv_db_v2.update_vm_network_port_count(context.session,
+                                                        vm_network_name,
+                                                        port_count)
+            self._process_portbindings_create_and_update(context,
+                                                         port['port'],
+                                                         pt)
+            # Extract policy profile for VM network create in VSM.
+            if not p_profile:
+                p_profile = n1kv_db_v2.get_policy_profile(session, profile_id)
+        try:
+            self._send_create_port_request(context,
+                                           pt,
+                                           port_count,
+                                           p_profile,
+                                           vm_network_name)
+        except(cisco_exceptions.VSMError,
+               cisco_exceptions.VSMConnectionFailed):
+            super(N1kvNeutronPluginV2, self).delete_port(context, pt['id'])
+        else:
+            LOG.debug(_("Created port: %s"), pt)
+            return pt
 
     def update_port(self, context, id, port):
         """
@@ -1240,9 +1251,21 @@ class N1kvNeutronPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
         if l3_port_check:
             self.prevent_l3_port_deletion(context, id)
         with context.session.begin(subtransactions=True):
+            port = self.get_port(context, id)
+            vm_network = n1kv_db_v2.get_vm_network(context.session,
+                                                   port[n1kv.PROFILE_ID],
+                                                   port['network_id'])
+            vm_network['port_count'] -= 1
+            n1kv_db_v2.update_vm_network_port_count(context.session,
+                                                    vm_network['name'],
+                                                    vm_network['port_count'])
+            if vm_network['port_count'] == 0:
+                n1kv_db_v2.delete_vm_network(context.session,
+                                             port[n1kv.PROFILE_ID],
+                                             port['network_id'])
             self.disassociate_floatingips(context, id)
-            self._send_delete_port_request(context, id)
             super(N1kvNeutronPluginV2, self).delete_port(context, id)
+        self._send_delete_port_request(context, port, vm_network)
 
     def get_port(self, context, id, fields=None):
         """
@@ -1381,22 +1404,22 @@ class N1kvNeutronPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
             net_p = super(N1kvNeutronPluginV2,
                           self).create_network_profile(context,
                                                        network_profile)
-            try:
-                self._send_create_logical_network_request(net_p,
-                                                          context.tenant_id)
-            except(cisco_exceptions.VSMError,
-                   cisco_exceptions.VSMConnectionFailed):
-                n1kv_db_v2.delete_profile_binding(context.session,
-                                                  context.tenant_id,
-                                                  net_p['id'])
-            try:
-                self._send_create_network_profile_request(context, net_p)
-            except(cisco_exceptions.VSMError,
-                   cisco_exceptions.VSMConnectionFailed):
-                n1kv_db_v2.delete_profile_binding(context.session,
-                                                  context.tenant_id,
-                                                  net_p['id'])
-                self._send_delete_logical_network_request(net_p)
+        try:
+            self._send_create_logical_network_request(net_p,
+                                                      context.tenant_id)
+        except(cisco_exceptions.VSMError,
+               cisco_exceptions.VSMConnectionFailed):
+            n1kv_db_v2.delete_profile_binding(context.session,
+                                              context.tenant_id,
+                                              net_p['id'])
+        try:
+            self._send_create_network_profile_request(context, net_p)
+        except(cisco_exceptions.VSMError,
+               cisco_exceptions.VSMConnectionFailed):
+            n1kv_db_v2.delete_profile_binding(context.session,
+                                              context.tenant_id,
+                                              net_p['id'])
+            self._send_delete_logical_network_request(net_p)
         return net_p
 
     def delete_network_profile(self, context, id):
@@ -1410,8 +1433,8 @@ class N1kvNeutronPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
         with context.session.begin(subtransactions=True):
             net_p = super(N1kvNeutronPluginV2,
                           self).delete_network_profile(context, id)
-            self._send_delete_network_profile_request(net_p)
-            self._send_delete_logical_network_request(net_p)
+        self._send_delete_network_profile_request(net_p)
+        self._send_delete_logical_network_request(net_p)
 
     def update_network_profile(self, context, net_profile_id, network_profile):
         """
@@ -1427,8 +1450,8 @@ class N1kvNeutronPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
                      update_network_profile(context,
                                             net_profile_id,
                                             network_profile))
-            self._send_update_network_profile_request(net_p)
-            return net_p
+        self._send_update_network_profile_request(net_p)
+        return net_p
 
     def create_router(self, context, router):
         """