]> review.fuel-infra Code Review - openstack-build/neutron-build.git/commitdiff
New tests are being adding to the Diablo code (Cisco L2-Network plugin), and some...
authorSumit Naiksatam <snaiksat@cisco.com>
Sun, 23 Oct 2011 03:03:22 +0000 (20:03 -0700)
committerSumit Naiksatam <snaiksat@cisco.com>
Sun, 23 Oct 2011 03:03:22 +0000 (20:03 -0700)
All changes contained within the Cisco L2-Network plugin and extensions.

Change-Id: I696a2aebeb9027f3b0ce0b6673910e02e304673f

23 files changed:
extensions/_novatenant_view.py
extensions/novatenant.py
quantum/plugins/cisco/README
quantum/plugins/cisco/common/cisco_configparser.py
quantum/plugins/cisco/common/cisco_constants.py
quantum/plugins/cisco/common/cisco_credentials.py
quantum/plugins/cisco/common/cisco_exceptions.py
quantum/plugins/cisco/common/cisco_utils.py
quantum/plugins/cisco/db/l2network_db.py
quantum/plugins/cisco/db/ucs_db.py
quantum/plugins/cisco/l2network_plugin.py
quantum/plugins/cisco/models/l2network_multi_blade.py
quantum/plugins/cisco/models/l2network_single_blade.py
quantum/plugins/cisco/nexus/cisco_nexus_plugin.py
quantum/plugins/cisco/nova/vifdirect.py
quantum/plugins/cisco/segmentation/l2network_vlan_mgr.py
quantum/plugins/cisco/tests/unit/test_l2networkApi.py
quantum/plugins/cisco/tests/unit/test_nexus_plugin.py
quantum/plugins/cisco/tests/unit/test_ucs_plugin.py
quantum/plugins/cisco/tests/unit/test_vlan_mgr.py [new file with mode: 0644]
quantum/plugins/cisco/ucs/cisco_ucs_inventory.py
quantum/plugins/cisco/ucs/cisco_ucs_network_driver.py
quantum/plugins/cisco/ucs/cisco_ucs_plugin.py

index b32ff8b644698f237097a20a5c20f6b24005bf83..64a27872a42790123c06e3e3a3f126a2a3ca6bbc 100644 (file)
@@ -45,3 +45,7 @@ class ViewBuilder(object):
     def build_vif(self, vif_data):
         """Return VIF description."""
         return dict(vif_desc=vif_data[const.VIF_DESC])
+
+    def build_result(self, result_data):
+        """Return result True/False"""
+        return dict(result=result_data)
index 5309ce29ee9802e45d29ea95ef09d47992bc4e2c..0460255d41d3dbc925f466167ad9ad543e085f7b 100644 (file)
@@ -64,7 +64,8 @@ class Novatenant(object):
         parent_resource = dict(member_name="tenant",
                                collection_name="extensions/csco/tenants")
         member_actions = {'schedule_host': "PUT",
-                          'associate_port': "PUT"}
+                          'associate_port': "PUT",
+                          'detach_port': "PUT"}
         controller = NovatenantsController(QuantumManager.get_plugin())
         return [extensions.ResourceExtension('novatenants', controller,
                                              parent=parent_resource,
@@ -154,3 +155,24 @@ class NovatenantsController(common.QuantumController):
             return result
         except qexception.PortNotFound as exp:
             return faults.Fault(faults.PortNotFound(exp))
+
+    def detach_port(self, request, tenant_id, id):
+        content_type = request.best_match_content_type()
+        try:
+            req_params = \
+                self._parse_request_params(request,
+                                           self._schedule_host_ops_param_list)
+        except exc.HTTPError as exp:
+            return faults.Fault(exp)
+
+        instance_id = req_params['instance_id']
+        instance_desc = req_params['instance_desc']
+
+        try:
+            vif = self._plugin. \
+            detach_port(tenant_id, instance_id, instance_desc)
+            builder = novatenant_view.get_view_builder(request)
+            result = builder.build_result(True)
+            return result
+        except qexception.PortNotFound as exp:
+            return faults.Fault(faults.PortNotFound(exp))
index 60c985c66a687e29a107c09c56899407668bcab2..ea9e78823353be739acc1032d039c8d5a20bcea1 100755 (executable)
@@ -205,7 +205,9 @@ password=mySecretPasswordForNexus
     quantum/plugins/cisco/conf/ucs_inventory.ini file. You can configure multiple\r
     UCSMs per deployment, multiple chassis per UCSM, and multiple blades per\r
     chassis. Chassis ID and blade ID can be obtained from the UCSM (they will\r
-    typically be numbers like 1, 2, 3, etc.)\r
+    typically be numbers like 1, 2, 3, etc.). Also make sure that you put the exact\r
+    hostname as nova sees it (the host column in the services table of the nova\r
+    DB will give you that information).\r
 \r
 [ucsm-1]\r
 ip_address = <put_ucsm_ip_address_here>\r
@@ -241,8 +243,8 @@ host_name = <put_hostname_here>
 Multi NIC support for VMs\r
 -------------------------\r
 As indicated earlier, if your Nova setup has a project with more than one network,\r
-Nova will try to create a vritual network interface (VIF) on the VM for each of those\r
-networks. That implies that,\r
+Nova will try to create a virtual network interface (VIF) on the VM for each of those\r
+networks. That implies -\r
 \r
     (1) You should create the same number of networks in Quantum as in your Nova\r
         project.\r
@@ -325,12 +327,18 @@ for Tenant: demo
     Note that when using UCS and the 802.1Qbh features, the association of the\r
     VIF-ID (also referred to as interface ID) on the VM's NIC with a port will\r
     happen automatically when the VM is instantiated. At this point, doing a\r
-    show_port will reveal the VIF-ID associated with the port.\r
+    show_port will reveal the VIF-ID associated with the port. To indicate that\r
+    this VIF-ID is still detached from the network it would eventually be on, you\r
+    will see the suffix "(detached)" on the VIF-ID. This indicates that although\r
+    the VIF-ID and the port have been associated, the VIF still does not have\r
+    connectivity to the network on which the port resides. That connectivity\r
+    will be established only after the plug/attach operation is performed (as\r
+    described in the next step).\r
 \r
 # PYTHONPATH=. python quantum/plugins/cisco/client/cli.py show_port demo c4a2bea7-a528-4caf-b16e-80397cd1663a 118ac473-294d-480e-8f6d-425acbbe81ae\r
 Logical Port ID: 118ac473-294d-480e-8f6d-425acbbe81ae\r
 administrative State: ACTIVE\r
-interface: b73e3585-d074-4379-8dde-931c0fc4db0e\r
+interface: b73e3585-d074-4379-8dde-931c0fc4db0e(detached)\r
 on Virtual Network: c4a2bea7-a528-4caf-b16e-80397cd1663a\r
 for Tenant: demo\r
 \r
@@ -347,17 +355,23 @@ for Tenant: demo
 \r
 \r
 8.  Unplug an interface and port from the network\r
-    Note: Before unplugging, make a note of the interface ID (you can use the\r
-    show_port CLI as before). While the VM, which has a VIF  with this interface\r
-    ID still exists, you can only plug that same interface back into this port.\r
-    So the subsequent plug interface operation on this port will have to make\r
-    use of the same interface ID.\r
 \r
 # PYTHONPATH=. python quantum/plugins/cisco/client/cli.py unplug_iface demo c4a2bea7-a528-4caf-b16e-80397cd1663a 118ac473-294d-480e-8f6d-425acbbe81ae\r
 Unplugged interface from Logical Port: 118ac473-294d-480e-8f6d-425acbbe81ae\r
 on Virtual Network: c4a2bea7-a528-4caf-b16e-80397cd1663a\r
 for Tenant: demo\r
 \r
+    Note: After unplugging, if you check the details of the port, you will\r
+    see the VIF-IF associated with the port (but now suffixed with the state\r
+    "detached"). At this point, it is possible to plug the VIF into the network\r
+    again making use of the same VIF-ID. In general, once associated, the VIF-ID\r
+    cannot be disassociated with the port until the VM is terminated. After the\r
+    VM is terminated, the VIF-ID will be automatically disassociated from the\r
+    port. To summarize, association and disassociation of the VIF-ID with a port\r
+    happens automatically at the time of creating and terminating the VM. The\r
+    connectivity of the VIF to the network is controlled by the user via the\r
+    plug and unplug operations.\r
+\r
 \r
 How to test the installation\r
 ----------------------------\r
index 33b2ff1275834f4cc68216cf4ba2e490b6789527..a96513787f7952d8428b188ab7b8df0813207cc7 100644 (file)
 #
 """
 
-import logging as LOG
 from configobj import ConfigObj
 from quantum.plugins.cisco.common import cisco_constants as const
 
-LOG.basicConfig(level=LOG.WARN)
-LOG.getLogger(const.LOGGER_COMPONENT_NAME)
-
 
 class CiscoConfigParser(ConfigObj):
     """Config Parser based on the ConfigObj module"""
index 3a99cb9f56b80bc50696b37486764fb72eeebf90..18b31a5a1c228dd0fe789ad83bc137591bbb14cc 100644 (file)
@@ -153,3 +153,13 @@ NETWORK_ADMIN = 'network_admin'
 NETID_LIST = 'net_id_list'
 
 DELIMITERS = "[,;:\b\s]"
+
+UUID_LENGTH = 36
+
+UNPLUGGED = '(detached)'
+
+ASSOCIATION_STATUS = 'association_status'
+
+ATTACHED = 'attached'
+
+DETACHED = 'detached'
index 02eab54690af56e8ae6fc4e0657e472d0620935a..e3f395f988cdf3df8d087991c3ad137ff98d6aac 100644 (file)
@@ -19,7 +19,6 @@
 #
 """
 
-import logging as LOG
 import os
 
 from quantum.plugins.cisco.common import cisco_configparser as confp
@@ -27,9 +26,6 @@ from quantum.plugins.cisco.common import cisco_constants as const
 from quantum.plugins.cisco.common import cisco_exceptions as cexc
 from quantum.plugins.cisco.db import l2network_db as cdb
 
-LOG.basicConfig(level=LOG.WARN)
-LOG.getLogger(const.LOGGER_COMPONENT_NAME)
-
 TENANT = const.NETWORK_ADMIN
 
 CREDENTIALS_FILE = "../conf/credentials.ini"
index 5decb9792a317dd639039eb1a470c232087fbf7c..cc775cf46520712726ab85fc08e08fe83fbffd3d 100644 (file)
@@ -176,6 +176,14 @@ class PortVnicNotFound(exceptions.QuantumException):
     message = _("PortVnic Binding %(port_id) is not present")
 
 
+class InvalidAttach(exceptions.QuantumException):
+    message = _("Unable to plug the attachment %(att_id)s into port " \
+                "%(port_id)s for network %(net_id)s. Association of " \
+                "attachment ID with port ID happens implicitly when " \
+                "VM is instantiated; attach operation can be " \
+                "performed subsequently.")
+
+
 try:
     _("test")
 except NameError:
index cbfd83727b52eca44b1b3371145a41e7040f23bd..ba6b07e3b1876292fc170e30781f0bb3b500ebda 100644 (file)
@@ -20,7 +20,7 @@
 """
 
 import hashlib
-import logging as LOG
+import logging
 import MySQLdb
 import traceback
 
@@ -28,8 +28,7 @@ from quantum.plugins.cisco.common import cisco_constants as const
 from quantum.plugins.cisco.db import api as db
 from quantum.plugins.cisco.db import l2network_db as cdb
 
-LOG.basicConfig(level=LOG.WARN)
-LOG.getLogger(const.LOGGER_COMPONENT_NAME)
+LOG = logging.getLogger(__name__)
 
 
 def get16ByteUUID(uuid):
index 30a1f5d36e503555a84113f7a1f2149486c1b3a9..f9b981948c3e893394a3f3d5ce892f27f09f41f2 100644 (file)
@@ -120,6 +120,8 @@ def reserve_vlanid():
         rvlan = session.query(l2network_models.VlanID).\
          filter_by(vlan_used=False).\
           first()
+        if not rvlan:
+            raise exc.NoResultFound
         rvlanid = session.query(l2network_models.VlanID).\
          filter_by(vlan_id=rvlan["vlan_id"]).\
           one()
index cfe2df27ec6c3faddf99c32da51e27944c469159..617542ffa4a028eca6115b85d9860d923327903b 100644 (file)
@@ -117,6 +117,38 @@ def update_portbinding(port_id, blade_intf_dn=None, portprofile_name=None,
         raise c_exc.PortVnicNotFound(port_id=port_id)
 
 
+def update_portbinding_instance_id(port_id, instance_id):
+    """Updates port binding for the instance ID"""
+    LOG.debug("db update_portbinding_instance_id() called")
+    session = db.get_session()
+    try:
+        port_binding = session.query(ucs_models.PortBinding).\
+          filter_by(port_id=port_id).\
+          one()
+        port_binding.instance_id = instance_id
+        session.merge(port_binding)
+        session.flush()
+        return port_binding
+    except exc.NoResultFound:
+        raise c_exc.PortVnicNotFound(port_id=port_id)
+
+
+def update_portbinding_vif_id(port_id, vif_id):
+    """Updates port binding for the VIF ID"""
+    LOG.debug("db update_portbinding_vif_id() called")
+    session = db.get_session()
+    try:
+        port_binding = session.query(ucs_models.PortBinding).\
+          filter_by(port_id=port_id).\
+          one()
+        port_binding.vif_id = vif_id
+        session.merge(port_binding)
+        session.flush()
+        return port_binding
+    except exc.NoResultFound:
+        raise c_exc.PortVnicNotFound(port_id=port_id)
+
+
 def get_portbinding_dn(blade_intf_dn):
     """Lists a port binding"""
     LOG.debug("get_portbinding_dn() called")
index dfd05b39c891407e4ee1ba3af75feeba6d3e42dc..9b3b60701ef4512a73f87eb270eb5eec5b6d54ae 100644 (file)
@@ -20,7 +20,7 @@
 """
 
 import inspect
-import logging as LOG
+import logging
 import re
 
 from quantum.common import exceptions as exc
@@ -35,8 +35,7 @@ from quantum.plugins.cisco.common import cisco_utils as cutil
 from quantum.plugins.cisco.db import api as db
 from quantum.plugins.cisco.db import l2network_db as cdb
 
-LOG.basicConfig(level=LOG.WARN)
-LOG.getLogger(const.LOGGER_COMPONENT_NAME)
+LOG = logging.getLogger(__name__)
 
 
 class L2Network(QuantumPluginBase):
@@ -246,35 +245,50 @@ class L2Network(QuantumPluginBase):
     def plug_interface(self, tenant_id, net_id, port_id,
                        remote_interface_id):
         """
-        Attaches a remote interface to the specified port on the
+        Provides connectivity to a remote interface to the
         specified Virtual Network.
         """
         LOG.debug("plug_interface() called\n")
         network = db.network_get(net_id)
         port = db.port_get(net_id, port_id)
         attachment_id = port[const.INTERFACEID]
-        if attachment_id and remote_interface_id != attachment_id:
+        if attachment_id == None:
+            raise cexc.InvalidAttach(port_id=port_id, net_id=net_id,
+                                    att_id=remote_interface_id)
+        attachment_id = attachment_id[:const.UUID_LENGTH]
+        remote_interface_id = remote_interface_id[:const.UUID_LENGTH]
+        if remote_interface_id != attachment_id:
+            LOG.debug("Existing attachment_id:%s, remote_interface_id:%s" % \
+                      (attachment_id, remote_interface_id))
             raise exc.PortInUse(port_id=port_id, net_id=net_id,
                                 att_id=attachment_id)
         self._invoke_device_plugins(self._func_name(), [tenant_id,
                                                         net_id, port_id,
-                                                        remote_interface_id])
-        if attachment_id == None:
-            db.port_set_attachment(net_id, port_id, remote_interface_id)
+                                                        attachment_id])
+        db.port_unset_attachment(net_id, port_id)
+        db.port_set_attachment(net_id, port_id, attachment_id)
         #Note: The remote_interface_id gets associated with the port
         # when the VM is instantiated. The plug interface call results
         # in putting the port on the VLAN associated with this network
 
     def unplug_interface(self, tenant_id, net_id, port_id):
         """
-        Detaches a remote interface from the specified port on the
+        Removes connectivity of a remote interface to the
         specified Virtual Network.
         """
         LOG.debug("unplug_interface() called\n")
         network = db.network_get(net_id)
+        port = db.port_get(net_id, port_id)
+        attachment_id = port[const.INTERFACEID]
+        if attachment_id == None:
+            raise exc.InvalidDetach(port_id=port_id, net_id=net_id,
+                                    att_id=remote_interface_id)
         self._invoke_device_plugins(self._func_name(), [tenant_id, net_id,
                                                      port_id])
+        attachment_id = attachment_id[:const.UUID_LENGTH]
+        attachment_id = attachment_id + const.UNPLUGGED
         db.port_unset_attachment(net_id, port_id)
+        db.port_set_attachment(net_id, port_id, attachment_id)
 
     """
     Extension API implementation
@@ -473,13 +487,22 @@ class L2Network(QuantumPluginBase):
 
     def associate_port(self, tenant_id, instance_id, instance_desc):
         """
-        Get the portprofile name and the device namei for the dynamic vnic
+        Get the portprofile name and the device name for the dynamic vnic
         """
         LOG.debug("associate_port() called\n")
         return self._invoke_device_plugins(self._func_name(), [tenant_id,
                                                                instance_id,
                                                                instance_desc])
 
+    def detach_port(self, tenant_id, instance_id, instance_desc):
+        """
+        Remove the association of the VIF with the dynamic vnic
+        """
+        LOG.debug("detach_port() called\n")
+        return self._invoke_device_plugins(self._func_name(), [tenant_id,
+                                                               instance_id,
+                                                               instance_desc])
+
     def create_multiport(self, tenant_id, net_id_list, port_state, ports_desc):
         """
         Creates multiple ports on the specified Virtual Network.
index a3967025ada02fbf9d530becdb8957f7c4e33b43..539f360eeb092e9de21e5a343733e584d9878639 100644 (file)
@@ -21,7 +21,7 @@
 
 from copy import deepcopy
 import inspect
-import logging as LOG
+import logging
 import platform
 
 from quantum.common import exceptions as exc
@@ -31,8 +31,7 @@ from quantum.plugins.cisco import l2network_plugin_configuration as conf
 from quantum.plugins.cisco.common import cisco_constants as const
 from quantum.plugins.cisco.common import cisco_exceptions as cexc
 
-LOG.basicConfig(level=LOG.WARN)
-LOG.getLogger(__name__)
+LOG = logging.getLogger(__name__)
 
 
 class L2NetworkMultiBlade(L2NetworkModelBase):
@@ -182,12 +181,20 @@ class L2NetworkMultiBlade(L2NetworkModelBase):
 
     def associate_port(self, args):
         """
-        Get the portprofile name and the device namei for the dynamic vnic
+        Get the portprofile name and the device name for the dynamic vnic
         """
         LOG.debug("associate_port() called\n")
         return self._invoke_inventory(const.UCS_PLUGIN, self._func_name(),
                                       args)
 
+    def detach_port(self, args):
+        """
+        Remove the association of the VIF with the dynamic vnic
+        """
+        LOG.debug("detach_port() called\n")
+        return self._invoke_plugin_per_device(const.UCS_PLUGIN,
+                                              self._func_name(), args)
+
     def create_multiport(self, args):
         """Support for extension  API call"""
         self._invoke_plugin_per_device(const.UCS_PLUGIN, self._func_name(),
index 5636c066527f306685fd1bd227739f010c561367..4184edb4b981aa90953bd5caf3adbcf9fce30082 100644 (file)
@@ -21,7 +21,7 @@
 
 from copy import deepcopy
 import inspect
-import logging as LOG
+import logging
 import platform
 
 from quantum.common import exceptions as exc
@@ -31,8 +31,7 @@ from quantum.plugins.cisco import l2network_plugin_configuration as conf
 from quantum.plugins.cisco.common import cisco_constants as const
 from quantum.plugins.cisco.common import cisco_exceptions as cexc
 
-LOG.basicConfig(level=LOG.WARN)
-LOG.getLogger(__name__)
+LOG = logging.getLogger(__name__)
 
 
 class L2NetworkSingleBlade(L2NetworkModelBase):
@@ -163,6 +162,14 @@ class L2NetworkSingleBlade(L2NetworkModelBase):
         return self._invoke_inventory(const.UCS_PLUGIN, self._func_name(),
                                       args)
 
+    def detach_port(self, args):
+        """
+        Remove the association of the VIF with the dynamic vnic
+        """
+        LOG.debug("detach_port() called\n")
+        return self._invoke_plugin_per_device(const.UCS_PLUGIN,
+                                              self._func_name(), args)
+
     def create_multiport(self, args):
         """Support for extension  API call"""
         self._invoke_plugin_per_device(const.UCS_PLUGIN, self._func_name(),
index dd93cf10e393e71495df7bc68e75bb7efdaf5d18..6c752832e489051f74b41b044bcd97433b8cffd7 100644 (file)
@@ -26,6 +26,8 @@ from quantum.common import exceptions as exc
 from quantum.common import utils
 from quantum.plugins.cisco.common import cisco_constants as const
 from quantum.plugins.cisco.common import cisco_credentials as cred
+from quantum.plugins.cisco.db import api as db
+from quantum.plugins.cisco.db import l2network_db as cdb
 from quantum.plugins.cisco.db import nexus_db as nxos_db
 from quantum.plugins.cisco.l2device_plugin_base import L2DevicePluginBase
 from quantum.plugins.cisco.nexus import cisco_nexus_configuration as conf
@@ -94,13 +96,12 @@ class NexusPlugin(L2DevicePluginBase):
         ports_id = nxos_db.get_nexusport_binding(vlan_id)
         LOG.debug("NexusPlugin: Interfaces to be disassociated: %s" % ports_id)
         nxos_db.remove_nexusport_binding(vlan_id)
-        net = self._networks.get(net_id)
+        net = self._get_network(tenant_id, net_id)
         if net:
             self._client.delete_vlan(str(vlan_id), self._nexus_ip,
                 self._nexus_username, self._nexus_password,
                 self._nexus_first_port, self._nexus_second_port,
                 self._nexus_ssh_port)
-            self._networks.pop(net_id)
             return net
         # Network not found
         raise exc.NetworkNotFound(net_id=net_id)
@@ -185,7 +186,11 @@ class NexusPlugin(L2DevicePluginBase):
         """
         Gets the NETWORK ID
         """
-        network = self._networks.get(network_id)
+        network = db.network_get(network_id)
         if not network:
             raise exc.NetworkNotFound(net_id=network_id)
-        return network
+        vlan = cdb.get_vlan_binding(network_id)
+        return {const.NET_ID: network_id, const.NET_NAME: network.name,
+                const.NET_PORTS: network.ports,
+                const.NET_VLAN_NAME: vlan.vlan_name,
+                const.NET_VLAN_ID: vlan.vlan_id}
index 015c9acebf65f1dc5bdaeef38d31d3315784f21d..cfc89129835305017928eaf8599c23036beaa6e2 100644 (file)
@@ -45,11 +45,12 @@ ACTION_PREFIX_CSCO = ACTION_PREFIX_EXT + \
         '/extensions/csco/tenants/{tenant_id}'
 TENANT_ID = 'nova'
 CSCO_EXT_NAME = 'Cisco Nova Tenant'
-ACTION = '/associate_port'
+ASSOCIATE_ACTION = '/associate_port'
+DETACH_ACTION = '/detach_port'
 
 
 class Libvirt802dot1QbhDriver(VIFDriver):
-    """VIF driver for Linux bridge."""
+    """VIF driver for 802.1Qbh"""
     def __init__(self):
         # We have to send a dummy tenant name here since the client
         # needs some tenant name, but the tenant name will not be used
@@ -70,7 +71,7 @@ class Libvirt802dot1QbhDriver(VIFDriver):
                   % CSCO_EXT_NAME)
         raise excp.ServiceUnavailable()
 
-    def _get_configurations(self, instance, network, mapping):
+    def _update_configurations(self, instance, network, mapping, action):
         """Gets the device name and the profile name from Quantum"""
 
         instance_id = instance['id']
@@ -88,26 +89,31 @@ class Libvirt802dot1QbhDriver(VIFDriver):
 
         client = Client(HOST, PORT, USE_SSL, format='json', tenant=TENANT_ID,
                         action_prefix=ACTION_PREFIX_CSCO)
-        request_url = "/novatenants/" + project_id + ACTION
+        request_url = "/novatenants/" + project_id + action
         data = client.do_request('PUT', request_url, body=instance_data_dict)
 
-        device = data['vif_desc']['device']
-        portprofile = data['vif_desc']['portprofile']
-        LOG.debug(_("Quantum provided the device: %s") % device)
-        LOG.debug(_("Quantum provided the portprofile: %s") % portprofile)
-        mac_id = mapping['mac'].replace(':', '')
+        if action == ASSOCIATE_ACTION:
+            device = data['vif_desc']['device']
+            portprofile = data['vif_desc']['portprofile']
+            LOG.debug(_("Quantum provided the device: %s") % device)
+            LOG.debug(_("Quantum provided the portprofile: %s") % portprofile)
+            mac_id = mapping['mac'].replace(':', '')
 
-        result = {
-            'id': mac_id,
-            'mac_address': mapping['mac'],
-            'device_name': device,
-            'profile_name': portprofile,
-        }
+            result = {
+                'id': mac_id,
+                'mac_address': mapping['mac'],
+                'device_name': device,
+                'profile_name': portprofile,
+            }
 
-        return result
+            return result
+        else:
+            return data
 
     def plug(self, instance, network, mapping):
-        return self._get_configurations(instance, network, mapping)
+        return self._update_configurations(instance, network, mapping,
+                                           ASSOCIATE_ACTION)
 
     def unplug(self, instance, network, mapping):
-        pass
+        self._update_configurations(instance, network, mapping,
+                                    DETACH_ACTION)
index f361980a4de3588d46d7a5265c91395934b39d4f..c60a1afd95debaf810ff9b3f9e9e223a72830b81 100644 (file)
 #
 """
 
-import logging as LOG
+import logging
 
 from quantum.plugins.cisco.common import cisco_constants as const
 from quantum.plugins.cisco.db import l2network_db as cdb
 from quantum.plugins.cisco.l2network_segmentation_base \
         import L2NetworkSegmentationMgrBase
 
-LOG.basicConfig(level=LOG.WARN)
-LOG.getLogger(const.LOGGER_COMPONENT_NAME)
+LOG = logging.getLogger(__name__)
 
 
 class L2NetworkVLANMgr(L2NetworkSegmentationMgrBase):
index 7b4bfac737edebaced5df69858876c2b2552b46c..92c0aed1dec17611f61178117ce5df3d9a425b16 100644 (file)
@@ -88,7 +88,11 @@ class CoreAPITestFunc(unittest.TestCase):
             tenant_id, net_id)
         LOG.debug("test_delete_network_not_found - END")
 
-    def test_delete_networkInUse(self, tenant_id='test_network'):
+    def test_delete_networkInUse(
+                    self, tenant_id='test_tenant', instance_tenant_id='nova',
+                    nova_user_id='novaadmin', instance_id=10,
+                    vif_id='fe701ddf-26a2-42ea-b9e6-7313d1c522cc'):
+
         """
         Tests deletion of a Virtual Network when Network is in Use.
         """
@@ -98,15 +102,24 @@ class CoreAPITestFunc(unittest.TestCase):
                                 tenant_id, self.network_name)
         port_dict = self._l2network_plugin.create_port(
                 tenant_id, new_net_dict[const.NET_ID], self.port_state)
-        self._l2network_plugin.plug_interface(
-                        tenant_id, new_net_dict[const.NET_ID],
-                        port_dict[const.PORT_ID], self.remote_interface)
+        instance_desc = {'project_id': tenant_id,
+                         'user_id': nova_user_id}
+        host_list = self._l2network_plugin.schedule_host(instance_tenant_id,
+                                                         instance_id,
+                                                         instance_desc)
+        instance_vif_desc = {'project_id': tenant_id,
+                             'user_id': nova_user_id,
+                             'vif_id': vif_id}
+        vif_description = self._l2network_plugin.associate_port(
+                                 instance_tenant_id, instance_id,
+                                 instance_vif_desc)
+
         self.assertRaises(exc.NetworkInUse,
                           self._l2network_plugin.delete_network, tenant_id,
                           new_net_dict[const.NET_ID])
         self.tearDownNetworkPortInterface(
-                        tenant_id, new_net_dict[const.NET_ID],
-                        port_dict[const.PORT_ID])
+                 tenant_id, instance_tenant_id, instance_id, instance_vif_desc,
+                 new_net_dict[const.NET_ID], port_dict[const.PORT_ID])
         LOG.debug("test_delete_networkInUse - END")
 
     def test_show_network(self, net_tenant_id=None):
@@ -330,7 +343,10 @@ class CoreAPITestFunc(unittest.TestCase):
         self.tearDownNetwork(tenant_id, new_net_dict[const.NET_ID])
         LOG.debug("test_delete_portDNE - END")
 
-    def test_delete_portInUse(self, tenant_id='test_tenant'):
+    def test_delete_portInUse(
+                    self, tenant_id='test_tenant', instance_tenant_id='nova',
+                    nova_user_id='novaadmin', instance_id=10,
+                    vif_id='fe701ddf-26a2-42ea-b9e6-7313d1c522cc'):
         """
         Tests deletion of Ports when port is in Use.
         """
@@ -341,14 +357,23 @@ class CoreAPITestFunc(unittest.TestCase):
         port_dict = self._l2network_plugin.create_port(
                                 tenant_id, new_net_dict[const.NET_ID],
                                 self.port_state)
-        self._l2network_plugin.plug_interface(
-                        tenant_id, new_net_dict[const.NET_ID],
-                        port_dict[const.PORT_ID], self.remote_interface)
+        instance_desc = {'project_id': tenant_id,
+                         'user_id': nova_user_id}
+        host_list = self._l2network_plugin.schedule_host(instance_tenant_id,
+                                                         instance_id,
+                                                         instance_desc)
+        instance_vif_desc = {'project_id': tenant_id,
+                             'user_id': nova_user_id,
+                             'vif_id': vif_id}
+        vif_description = self._l2network_plugin.associate_port(
+                                 instance_tenant_id, instance_id,
+                                 instance_vif_desc)
         self.assertRaises(exc.PortInUse,
                           self._l2network_plugin.delete_port, tenant_id,
                           new_net_dict[const.NET_ID], port_dict[const.PORT_ID])
         self.tearDownNetworkPortInterface(
-              tenant_id, new_net_dict[const.NET_ID], port_dict[const.PORT_ID])
+                 tenant_id, instance_tenant_id, instance_id, instance_vif_desc,
+                 new_net_dict[const.NET_ID], port_dict[const.PORT_ID])
         LOG.debug("test_delete_portInUse - END")
 
     def test_update_port(self, tenant_id='test_tenant',
@@ -446,8 +471,10 @@ class CoreAPITestFunc(unittest.TestCase):
         self.tearDownNetwork(tenant_id, new_net_dict[const.NET_ID])
         LOG.debug("test_show_portDNE - END")
 
-    def test_plug_interface(self, tenant_id='test_tenant',
-                            remote_interface='new_interface'):
+    def test_plug_interface(
+                    self, tenant_id='test_tenant', instance_tenant_id='nova',
+                    nova_user_id='novaadmin', instance_id=10,
+                    vif_id='fe701ddf-26a2-42ea-b9e6-7313d1c522cc'):
         """
         Tests attachment of interface to the port
         """
@@ -457,15 +484,28 @@ class CoreAPITestFunc(unittest.TestCase):
                                 tenant_id, self.network_name)
         port_dict = self._l2network_plugin.create_port(
                         tenant_id, new_net_dict[const.NET_ID], self.port_state)
+        instance_desc = {'project_id': tenant_id,
+                         'user_id': nova_user_id}
+        host_list = self._l2network_plugin.schedule_host(instance_tenant_id,
+                                                         instance_id,
+                                                         instance_desc)
+        instance_vif_desc = {'project_id': tenant_id,
+                             'user_id': nova_user_id,
+                             'vif_id': vif_id}
+        vif_description = self._l2network_plugin.associate_port(
+                                 instance_tenant_id, instance_id,
+                                 instance_vif_desc)
+
         self._l2network_plugin.plug_interface(
                         tenant_id, new_net_dict[const.NET_ID],
-                        port_dict[const.PORT_ID], remote_interface)
+                        port_dict[const.PORT_ID], vif_id)
         port = db.port_get(new_net_dict[const.NET_ID],
                            port_dict[const.PORT_ID])
-        self.assertEqual(port[const.INTERFACEID], remote_interface)
+        self.assertEqual(port[const.INTERFACEID], vif_id)
         self.tearDownNetworkPortInterface(
-                        tenant_id, new_net_dict[const.NET_ID],
-                        port_dict[const.PORT_ID])
+                 tenant_id, instance_tenant_id, instance_id, instance_vif_desc,
+                 new_net_dict[const.NET_ID], port_dict[const.PORT_ID])
+
         LOG.debug("test_plug_interface - END")
 
     def test_plug_interface_networkDNE(
@@ -497,8 +537,11 @@ class CoreAPITestFunc(unittest.TestCase):
         self.tearDownNetwork(tenant_id, new_net_dict[const.NET_ID])
         LOG.debug("test_plug_interface_portDNE - END")
 
-    def test_plug_interface_portInUse(self, tenant_id='test_tenant',
-                                      remote_interface='new_interface'):
+    def test_plug_interface_portInUse(
+                  self, tenant_id='test_tenant', instance_tenant_id='nova',
+                  nova_user_id='novaadmin', instance_id=10,
+                  vif_id='fe701ddf-26a2-42ea-b9e6-7313d1c522cc',
+                  remote_interface='new_interface'):
 
         """
         Tests attachment of new interface to the port when there is an
@@ -506,24 +549,37 @@ class CoreAPITestFunc(unittest.TestCase):
         """
 
         LOG.debug("test_plug_interface_portInUse - START")
-        current_interface = "current_interface"
         new_net_dict = self._l2network_plugin.create_network(
                                 tenant_id, self.network_name)
         port_dict = self._l2network_plugin.create_port(
                         tenant_id, new_net_dict[const.NET_ID], self.port_state)
-        self._l2network_plugin.plug_interface(
-                        tenant_id, new_net_dict[const.NET_ID],
-                        port_dict[const.PORT_ID], current_interface)
+        instance_desc = {'project_id': tenant_id,
+                         'user_id': nova_user_id}
+        host_list = self._l2network_plugin.schedule_host(instance_tenant_id,
+                                                         instance_id,
+                                                         instance_desc)
+        instance_vif_desc = {'project_id': tenant_id,
+                             'user_id': nova_user_id,
+                             'vif_id': vif_id}
+        vif_description = self._l2network_plugin.associate_port(
+                                 instance_tenant_id, instance_id,
+                                 instance_vif_desc)
+
         self.assertRaises(exc.PortInUse,
                               self._l2network_plugin.plug_interface, tenant_id,
                               new_net_dict[const.NET_ID],
-                          port_dict[const.PORT_ID], remote_interface)
+                              port_dict[const.PORT_ID], remote_interface)
         self.tearDownNetworkPortInterface(
-                        tenant_id, new_net_dict[const.NET_ID],
-                        port_dict[const.PORT_ID])
+                 tenant_id, instance_tenant_id, instance_id, instance_vif_desc,
+                 new_net_dict[const.NET_ID], port_dict[const.PORT_ID])
+
         LOG.debug("test_plug_interface_portInUse - END")
 
-    def test_unplug_interface(self, tenant_id='test_tenant'):
+    def test_unplug_interface(
+                    self, tenant_id='test_tenant', instance_tenant_id='nova',
+                    nova_user_id='novaadmin', instance_id=10,
+                    vif_id='fe701ddf-26a2-42ea-b9e6-7313d1c522cc'):
+
         """
         Tests detaachment of an interface to a port
         """
@@ -534,17 +590,32 @@ class CoreAPITestFunc(unittest.TestCase):
         port_dict = self._l2network_plugin.create_port(
                                 tenant_id, new_net_dict[const.NET_ID],
                                 self.port_state)
+        instance_desc = {'project_id': tenant_id,
+                         'user_id': nova_user_id}
+        host_list = self._l2network_plugin.schedule_host(instance_tenant_id,
+                                                         instance_id,
+                                                         instance_desc)
+        instance_vif_desc = {'project_id': tenant_id,
+                             'user_id': nova_user_id,
+                             'vif_id': vif_id}
+        vif_description = self._l2network_plugin.associate_port(
+                                 instance_tenant_id, instance_id,
+                                 instance_vif_desc)
+
         self._l2network_plugin.plug_interface(
                         tenant_id, new_net_dict[const.NET_ID],
-                        port_dict[const.PORT_ID], self.remote_interface)
+                        port_dict[const.PORT_ID], vif_id)
         self._l2network_plugin.unplug_interface(
                         tenant_id, new_net_dict[const.NET_ID],
                         port_dict[const.PORT_ID])
         port = db.port_get(new_net_dict[const.NET_ID],
                            port_dict[const.PORT_ID])
-        self.assertEqual(port[const.INTERFACEID], None)
-        self.tearDownNetworkPort(tenant_id, new_net_dict[const.NET_ID],
-                                 port_dict[const.PORT_ID])
+        vif_id_unplugged = vif_id + '(detached)'
+        self.assertEqual(port[const.INTERFACEID], vif_id_unplugged)
+        self.tearDownNetworkPortInterface(
+                 tenant_id, instance_tenant_id, instance_id, instance_vif_desc,
+                 new_net_dict[const.NET_ID], port_dict[const.PORT_ID])
+
         LOG.debug("test_unplug_interface - END")
 
     def test_unplug_interface_networkDNE(self, tenant_id='test_tenant',
@@ -926,13 +997,14 @@ class CoreAPITestFunc(unittest.TestCase):
         self._l2network_plugin.delete_port(tenant_id, network_dict_id, port_id)
         self.tearDownNetwork(tenant_id, network_dict_id)
 
-    def tearDownNetworkPortInterface(self, tenant_id, network_dict_id,
-                                     port_id):
+    def tearDownNetworkPortInterface(self, tenant_id, instance_tenant_id,
+                                  instance_id, instance_desc, network_dict_id,
+                                  port_id):
         """
         Tear down Network Port Interface
         """
-        self._l2network_plugin.unplug_interface(tenant_id,
-                                                network_dict_id, port_id)
+        self._l2network_plugin.detach_port(instance_tenant_id, instance_id,
+                                           instance_desc)
         self.tearDownNetworkPort(tenant_id, network_dict_id, port_id)
 
     def tearDownPortProfile(self, tenant_id, port_profile_id):
index 65711e7c0e0a4ee8bf3d7ece629229de8a7b2b7f..bb8f4b2bd61a00e2cc83140c10984a0dfd47a62e 100644 (file)
@@ -20,6 +20,7 @@ from quantum.common import exceptions as exc
 from quantum.plugins.cisco.common import cisco_constants as const
 from quantum.plugins.cisco.db import l2network_db as cdb
 from quantum.plugins.cisco.db import api as db
+from quantum.plugins.cisco.common import cisco_credentials as cred
 from quantum.plugins.cisco.nexus import cisco_nexus_plugin
 
 LOG = logging.getLogger('quantum.tests.test_nexus')
@@ -31,7 +32,6 @@ class TestNexusPlugin(unittest.TestCase):
         """
         Set up function
         """
-
         self.tenant_id = "test_tenant_cisco1"
         self.net_name = "test_network_cisco1"
         self.net_id = 000007
@@ -39,11 +39,11 @@ class TestNexusPlugin(unittest.TestCase):
         self.vlan_id = 267
         self.port_id = "9"
         cdb.initialize()
+        cred.Store.initialize()
         self._cisco_nexus_plugin = cisco_nexus_plugin.NexusPlugin()
 
     def test_create_network(self, net_tenant_id=None, network_name=None,
-                            network_id=None, net_vlan_name=None,
-                            net_vlan_id=None):
+                            net_vlan_name=None, net_vlan_id=None):
         """
         Tests creation of new Virtual Network.
         """
@@ -57,10 +57,6 @@ class TestNexusPlugin(unittest.TestCase):
             net_name = network_name
         else:
             net_name = self.net_name
-        if network_id:
-            net_id = network_id
-        else:
-            net_id = self.net_id
         if net_vlan_name:
             vlan_name = net_vlan_name
         else:
@@ -70,18 +66,20 @@ class TestNexusPlugin(unittest.TestCase):
         else:
             vlan_id = self.vlan_id
 
-        network_created = self.create_network(tenant_id, net_id)
+        network_created = self.create_network(tenant_id, net_name)
         cdb.add_vlan_binding(vlan_id, vlan_name, network_created["net-id"])
         new_net_dict = self._cisco_nexus_plugin.create_network(
-                tenant_id, net_name, net_id, vlan_name, vlan_id)
-        self.assertEqual(new_net_dict[const.NET_ID], self.net_id)
+                            tenant_id, net_name, network_created["net-id"],
+                            vlan_name, vlan_id)
+        self.assertEqual(new_net_dict[const.NET_ID],
+                         network_created["net-id"])
         self.assertEqual(new_net_dict[const.NET_NAME], self.net_name)
         self.assertEqual(new_net_dict[const.NET_VLAN_NAME], self.vlan_name)
         self.assertEqual(new_net_dict[const.NET_VLAN_ID], self.vlan_id)
         self.tearDownNetwork(tenant_id, new_net_dict[const.NET_ID])
         LOG.debug("test_create_network - END")
 
-    def test_delete_network(self, net_tenant_id=None, network_id=None):
+    def test_delete_network(self, net_tenant_id=None, network_name=None):
         """
         Tests deletion of a Virtual Network.
         """
@@ -92,16 +90,21 @@ class TestNexusPlugin(unittest.TestCase):
             tenant_id = net_tenant_id
         else:
             tenant_id = self.tenant_id
-        if network_id:
-            net_id = network_id
+        if network_name:
+            net_name = network_name
         else:
-            net_id = self.net_id
+            net_name = self.net_name
 
+        network_created = self.create_network(tenant_id, net_name)
+        cdb.add_vlan_binding(self.vlan_id, self.vlan_name,
+                             network_created["net-id"])
         new_net_dict = self._cisco_nexus_plugin.create_network(
-                tenant_id, self.net_name, net_id, self.vlan_name, self.vlan_id)
+                           tenant_id, self.net_name, network_created["net-id"],
+                           self.vlan_name, self.vlan_id)
         deleted_net_dict = self._cisco_nexus_plugin.delete_network(
                         tenant_id, new_net_dict[const.NET_ID])
-        self.assertEqual(deleted_net_dict[const.NET_ID], net_id)
+        self.assertEqual(deleted_net_dict[const.NET_ID],
+                         network_created["net-id"])
         LOG.debug("test_delete_network - END")
 
     def test_delete_network_DNE(self, net_tenant_id=None, net_id='0005'):
@@ -122,7 +125,7 @@ class TestNexusPlugin(unittest.TestCase):
 
         LOG.debug("test_delete_network_DNE - END")
 
-    def test_get_network_details(self, net_tenant_id=None, network_id=None):
+    def test_get_network_details(self, net_tenant_id=None, network_name=None):
         """
         Tests displays details of a Virtual Network .
         """
@@ -133,17 +136,21 @@ class TestNexusPlugin(unittest.TestCase):
             tenant_id = net_tenant_id
         else:
             tenant_id = self.tenant_id
-        if network_id:
-            net_id = network_id
+        if network_name:
+            net_name = network_name
         else:
-            net_id = self.net_id
+            net_name = self.net_name
 
+        network_created = self.create_network(tenant_id, net_name)
+        cdb.add_vlan_binding(self.vlan_id, self.vlan_name,
+                             network_created["net-id"])
         new_net_dict = self._cisco_nexus_plugin.create_network(
-                tenant_id, self.net_name, net_id, self.vlan_name, self.vlan_id)
+                           tenant_id, self.net_name, network_created["net-id"],
+                           self.vlan_name, self.vlan_id)
         check_net_dict = self._cisco_nexus_plugin.get_network_details(
-                                        tenant_id, net_id)
-
-        self.assertEqual(check_net_dict[const.NET_ID], net_id)
+                                        tenant_id, network_created["net-id"])
+        self.assertEqual(check_net_dict[const.NET_ID],
+                         network_created["net-id"])
         self.assertEqual(check_net_dict[const.NET_NAME], self.net_name)
         self.assertEqual(check_net_dict[const.NET_VLAN_NAME], self.vlan_name)
         self.assertEqual(check_net_dict[const.NET_VLAN_ID], self.vlan_id)
@@ -169,7 +176,7 @@ class TestNexusPlugin(unittest.TestCase):
         LOG.debug("test_get_network_details_network_does_not_exist - END")
 
     def test_rename_network(self, new_name="new_network_name",
-                            net_tenant_id=None, network_id=None):
+                            net_tenant_id=None, network_name=None):
         """
         Tests rename of a Virtual Network .
         """
@@ -180,14 +187,17 @@ class TestNexusPlugin(unittest.TestCase):
             tenant_id = net_tenant_id
         else:
             tenant_id = self.tenant_id
-        if network_id:
-            net_id = network_id
+        if network_name:
+            net_name = network_name
         else:
-            net_id = self.net_id
+            net_name = self.net_name
 
+        network_created = self.create_network(tenant_id, net_name)
+        cdb.add_vlan_binding(self.vlan_id, self.vlan_name,
+                             network_created["net-id"])
         new_net_dict = self._cisco_nexus_plugin.create_network(
-                        tenant_id, self.net_name, net_id, self.vlan_name,
-                        self.vlan_id)
+                           tenant_id, self.net_name, network_created["net-id"],
+                           self.vlan_name, self.vlan_id)
         rename_net_dict = self._cisco_nexus_plugin.rename_network(
                         tenant_id, new_net_dict[const.NET_ID], new_name)
         self.assertEqual(rename_net_dict[const.NET_NAME], new_name)
@@ -227,23 +237,28 @@ class TestNexusPlugin(unittest.TestCase):
             tenant_id = net_tenant_id
         else:
             tenant_id = self.tenant_id
+
+        network_created = self.create_network(tenant_id, self.net_name)
+        cdb.add_vlan_binding(self.vlan_id, self.vlan_name,
+                             network_created["net-id"])
         new_net_dict1 = self._cisco_nexus_plugin.create_network(
-                                tenant_id, self.net_name, self.net_id,
-                                self.vlan_name, self.vlan_id)
+                           tenant_id, self.net_name, network_created["net-id"],
+                           self.vlan_name, self.vlan_id)
+        network_created2 = self.create_network(tenant_id, 'test_network2')
+        cdb.add_vlan_binding(265, 'second_vlan', network_created2["net-id"])
         new_net_dict2 = self._cisco_nexus_plugin.create_network(
-                                tenant_id, "New_Network2", "0011",
-                                "second_vlan", "2003")
+                           tenant_id, "New_Network2",
+                           network_created2["net-id"], "second_vlan", "2003")
         list_net_dict = self._cisco_nexus_plugin.get_all_networks(tenant_id)
         net_temp_list = [new_net_dict1, new_net_dict2]
-        self.assertEqual(len(list_net_dict), 2)
-        self.assertTrue(list_net_dict[0] in net_temp_list)
-        self.assertTrue(list_net_dict[1] in net_temp_list)
+        self.assertTrue(net_temp_list[0] in list_net_dict)
+        self.assertTrue(net_temp_list[1] in list_net_dict)
         self.tearDownNetwork(tenant_id, new_net_dict1[const.NET_ID])
         self.tearDownNetwork(tenant_id, new_net_dict2[const.NET_ID])
         LOG.debug("test_list_all_networks - END")
 
     def test_get_vlan_id_for_network(self, net_tenant_id=None,
-                                     network_id=None):
+                                     network_name=None):
         """
         Tests retrieval of vlan id for a Virtual Networks .
         """
@@ -253,15 +268,19 @@ class TestNexusPlugin(unittest.TestCase):
             tenant_id = net_tenant_id
         else:
             tenant_id = self.tenant_id
-        if network_id:
-            net_id = network_id
+        if network_name:
+            net_name = network_name
         else:
-            net_id = self.net_id
+            net_name = self.net_name
+
+        network_created = self.create_network(tenant_id, net_name)
+        cdb.add_vlan_binding(self.vlan_id, self.vlan_name,
+                             network_created["net-id"])
         new_net_dict = self._cisco_nexus_plugin.create_network(
-                        tenant_id, self.net_name, net_id, self.vlan_name,
-                        self.vlan_id)
+                          tenant_id, self.net_name, network_created["net-id"],
+                          self.vlan_name, self.vlan_id)
         result_vlan_id = self._cisco_nexus_plugin._get_vlan_id_for_network(
-                        tenant_id, net_id)
+                        tenant_id, network_created["net-id"])
         self.assertEqual(result_vlan_id, self.vlan_id)
         self.tearDownNetwork(tenant_id, new_net_dict[const.NET_ID])
         LOG.debug("test_get_vlan_id_for_network - END")
@@ -284,3 +303,8 @@ class TestNexusPlugin(unittest.TestCase):
         Clean up functions after the tests
         """
         self._cisco_nexus_plugin.delete_network(tenant_id, network_dict_id)
+
+    def tearDown(self):
+        """Clear the test environment"""
+        # Remove database contents
+        db.clear_db()
index 6c1e54a70189544553339a69c613385626918e02..b8fa34de6e9313d52d7b093a72f1ad233d1b938c 100644 (file)
@@ -35,6 +35,9 @@ LOG.getLogger("cisco_ucs_plugin")
 
 
 class UCSVICTestPlugin(unittest.TestCase):
+    """
+    Unit Tests for the UCS Plugin functions
+    """
 
     def setUp(self):
 
@@ -49,10 +52,14 @@ class UCSVICTestPlugin(unittest.TestCase):
         self._cisco_ucs_plugin = cisco_ucs_plugin.UCSVICPlugin()
         self.device_ip = conf.UCSM_IP_ADDRESS
         self._ucs_inventory = ucsinv.UCSInventory()
-        self.chassis_id = '1'
-        self.blade_id = '5'
-        self.blade_intf_distinguished_name = 'sys/chassis-1/blade-5/'\
-                                             'adaptor-1/host-eth-6'
+        self._ucs_inventory._load_inventory()
+        self.chassis_id_list = self._ucs_inventory._inventory[\
+                               self.device_ip].keys()
+        self.chassis_id = self.chassis_id_list[0]
+        self.blade_id_list = self._ucs_inventory._inventory[\
+                             self.device_ip][self.chassis_id]
+        self.blade_id = self._ucs_inventory._inventory[\
+                             self.device_ip][self.chassis_id][0]
 
     def test_create_network(self):
         """
@@ -69,7 +76,7 @@ class UCSVICTestPlugin(unittest.TestCase):
         self.assertEqual(new_net_dict[const.NET_ID], new_network[const.UUID])
         self.assertEqual(new_net_dict[const.NET_NAME],
                          new_network[const.NETWORKNAME])
-        self.tearDownNetwork(self.tenant_id, new_network[const.UUID])
+        self.tear_down_network(self.tenant_id, new_network[const.UUID])
 
     def test_delete_network(self):
         """
@@ -107,7 +114,7 @@ class UCSVICTestPlugin(unittest.TestCase):
         self.assertEqual(new_net_dict[const.NET_ID], new_network[const.UUID])
         self.assertEqual(new_net_dict[const.NET_NAME],
                          new_network[const.NETWORKNAME])
-        self.tearDownNetwork(self.tenant_id, new_network[const.UUID])
+        self.tear_down_network(self.tenant_id, new_network[const.UUID])
 
     def test_get_all_networks(self):
         """
@@ -136,8 +143,8 @@ class UCSVICTestPlugin(unittest.TestCase):
 
         self.assertTrue(net_list[0] in net_id_list)
         self.assertTrue(net_list[1] in net_id_list)
-        self.tearDownNetwork(self.tenant_id, new_network1[const.UUID])
-        self.tearDownNetwork(self.tenant_id, new_network2[const.UUID])
+        self.tear_down_network(self.tenant_id, new_network1[const.UUID])
+        self.tear_down_network(self.tenant_id, new_network2[const.UUID])
 
     def test_get_all_ports(self):
         """
@@ -178,16 +185,18 @@ class UCSVICTestPlugin(unittest.TestCase):
         self.assertTrue(str(ports_on_net[0]) == str(port_list[1]) or
                         str(ports_on_net[0]) == str(port_list[0]))
 
+        blade_intf_details = self._ucs_inventory._get_rsvd_blade_intf_by_port(
+                                      self.tenant_id, port_dict1[const.PORTID])
         self._cisco_ucs_plugin.delete_port(
                      self.tenant_id, new_net_dict[const.NET_ID],
                      port_dict1[const.PORTID], device_ip=self.device_ip,
                      ucs_inventory=self._ucs_inventory,
                      chassis_id=self.chassis_id, blade_id=self.blade_id,
-                     blade_intf_distinguished_name=self.\
-                     blade_intf_distinguished_name,
+                     blade_intf_distinguished_name=blade_intf_details[\
+                     const.BLADE_INTF_DN],
                      least_rsvd_blade_dict=self._ucs_inventory.\
                      _get_least_reserved_blade())
-        self.tearDownNetworkPort(
+        self.tear_down_network_port(
                  self.tenant_id, new_net_dict[const.NET_ID],
                  port_dict2[const.PORTID])
 
@@ -215,7 +224,7 @@ class UCSVICTestPlugin(unittest.TestCase):
         profile_name = self._cisco_ucs_plugin.\
                            _get_profile_name(port_dict[const.PORTID])
         self.assertTrue(profile_name != None)
-        self.tearDownNetworkPort(
+        self.tear_down_network_port(
                  self.tenant_id, new_net_dict[const.NET_ID],
                  port_dict[const.PORTID])
 
@@ -241,18 +250,21 @@ class UCSVICTestPlugin(unittest.TestCase):
                             ucs_inventory=self._ucs_inventory,
                             least_rsvd_blade_dict=self._ucs_inventory.\
                             _get_least_reserved_blade())
+
+        blade_intf_details = self._ucs_inventory._get_rsvd_blade_intf_by_port(
+                                       self.tenant_id, port_dict[const.PORTID])
         port_bind = self._cisco_ucs_plugin.delete_port(
                          self.tenant_id, new_net_dict[const.NET_ID],
                          port_dict[const.PORTID], device_ip=self.device_ip,
                          ucs_inventory=self._ucs_inventory,
                          chassis_id=self.chassis_id, blade_id=self.blade_id,
-                         blade_intf_distinguished_name=self.\
-                         blade_intf_distinguished_name,
+                         blade_intf_distinguished_name=blade_intf_details[\
+                         const.BLADE_INTF_DN],
                          least_rsvd_blade_dict=self._ucs_inventory.\
                          _get_least_reserved_blade())
 
         self.assertEqual(port_bind[const.PORTID], new_port[const.UUID])
-        self.tearDownNetwork(self.tenant_id, new_net_dict[const.NET_ID])
+        self.tear_down_network(self.tenant_id, new_net_dict[const.NET_ID])
 
     def _test_get_port_details(self, port_state):
         """
@@ -279,17 +291,26 @@ class UCSVICTestPlugin(unittest.TestCase):
                             self.tenant_id, new_net_dict[const.NET_ID],
                             port_dict[const.PORTID], device_ip=self.device_ip)
         self.assertEqual(str(port_dict), str(port_detail))
-        self.tearDownNetworkPort(
+        self.tear_down_network_port(
                  self.tenant_id, new_net_dict[const.NET_ID],
                  port_dict[const.PORTID])
 
     def test_get_port_details_state_up(self):
+        """
+        Tests if the port details is retrieved when port is up
+        """
         self._test_get_port_details(const.PORT_UP)
 
     def test_show_port_state_down(self):
+        """
+        Tests if the port details is retrieved when port is down
+        """
         self._test_get_port_details(const.PORT_DOWN)
 
     def test_create_port_profile(self):
+        """
+        Tests creation of port profile
+        """
         LOG.debug("UCSVICTestPlugin:test_create_port_profile() called\n")
         new_network = db.network_create(self.tenant_id, self.net_name)
         cdb.add_vlan_binding(str(self.vlan_id), self.vlan_name,
@@ -310,6 +331,9 @@ class UCSVICTestPlugin(unittest.TestCase):
                                                     profile_name)
 
     def test_delete_port_profile(self):
+        """
+        Tests deletion of port profile
+        """
         LOG.debug("UCSVICTestPlugin:test_delete_port_profile() called\n")
         new_network = db.network_create(self.tenant_id, self.net_name)
         cdb.add_vlan_binding(str(self.vlan_id), self.vlan_name,
@@ -359,7 +383,7 @@ class UCSVICTestPlugin(unittest.TestCase):
                            device_ip=self.device_ip)
         self.assertEqual(port_bind[const.VLANNAME], new_vlan_name)
         self.assertEqual(port_bind[const.VLANID], new_vlanid)
-        self.tearDownNetworkPortInterface(
+        self.tear_down_network_port_interface(
                                    self.tenant_id, new_net_dict[const.NET_ID],
                                    new_port[const.UUID])
 
@@ -397,11 +421,14 @@ class UCSVICTestPlugin(unittest.TestCase):
                            port_dict[const.PORTID], device_ip=self.device_ip)
         self.assertEqual(port_bind[const.VLANNAME], self.vlan_name)
         self.assertEqual(port_bind[const.VLANID], self.vlan_id)
-        self.tearDownNetworkPortInterface(
+        self.tear_down_network_port_interface(
                                    self.tenant_id, new_net_dict[const.NET_ID],
                                    new_port[const.UUID])
 
     def test_get_vlan_name_for_network(self):
+        """
+        Tests retrieval of vlan name
+        """
         LOG.debug("UCSVICTestPlugin:test_get_vlan_name_for_network() called\n")
         new_network = db.network_create(self.tenant_id, self.net_name)
         cdb.add_vlan_binding(str(self.vlan_id), self.vlan_name,
@@ -412,6 +439,9 @@ class UCSVICTestPlugin(unittest.TestCase):
         self.assertEqual(vlan_bind_name, self.vlan_name)
 
     def test_get_vlan_id_for_network(self):
+        """
+        Tests retrieval of vlan id
+        """
         LOG.debug("UCSVICTestPlugin:test_get_vlan_id_for_network() called\n")
         new_network = db.network_create(self.tenant_id, self.net_name)
         cdb.add_vlan_binding(str(self.vlan_id), self.vlan_name,
@@ -420,19 +450,28 @@ class UCSVICTestPlugin(unittest.TestCase):
                                     self.tenant_id, new_network[const.UUID])
         self.assertEqual(str(vlan_bind_id), self.vlan_id)
 
-    def test_show_network_NetworkNotFound(self):
+    def test_show_network_not_found(self):
+        """
+        Negative Test for show network details when network not found
+        """
         self.assertRaises(exc.NetworkNotFound,
                           self._cisco_ucs_plugin.get_network_details,
                           self.tenant_id, self.net_id,
                           device_ip=self.device_ip)
 
-    def test_delete_network_NetworkNotFound(self):
+    def test_delete_network_not_found(self):
+        """
+        Negative Test for delete network when network not found
+        """
         self.assertRaises(exc.NetworkNotFound,
                           self._cisco_ucs_plugin.delete_network,
                           self.tenant_id, self.net_id,
                           device_ip=self.device_ip)
 
     def test_delete_port_PortNotFound(self):
+        """
+        Negative Test for delete port when port not found
+        """
         new_network = db.network_create(self.tenant_id, self.net_name)
         cdb.add_vlan_binding(str(self.vlan_id), self.vlan_name,
                              new_network[const.UUID])
@@ -447,35 +486,36 @@ class UCSVICTestPlugin(unittest.TestCase):
                           self.port_id, device_ip=self.device_ip,
                           ucs_inventory=self._ucs_inventory,
                           chassis_id=self.chassis_id, blade_id=self.blade_id,
-                          blade_intf_distinguished_name=self.\
-                          blade_intf_distinguished_name,
+                          blade_intf_distinguished_name=None,
                           least_rsvd_blade_dict=self._ucs_inventory.\
                           _get_least_reserved_blade())
 
-        self.tearDownNetwork(self.tenant_id, new_net_dict[const.NET_ID])
+        self.tear_down_network(self.tenant_id, new_net_dict[const.NET_ID])
 
     def tearDown(self):
         """Clear the test environment"""
         # Remove database contents
         db.clear_db()
 
-    def tearDownNetwork(self, tenant_id, net_id):
+    def tear_down_network(self, tenant_id, net_id):
         self._cisco_ucs_plugin.delete_network(tenant_id, net_id,
                                               device_ip=self.device_ip)
 
-    def tearDownNetworkPort(self, tenant_id, net_id, port_id):
+    def tear_down_network_port(self, tenant_id, net_id, port_id):
+        blade_intf_details = self._ucs_inventory._get_rsvd_blade_intf_by_port(
+                                                 tenant_id, port_id)
         self._cisco_ucs_plugin.delete_port(
                     tenant_id, net_id, port_id, device_ip=self.device_ip,
                     ucs_inventory=self._ucs_inventory,
                     chassis_id=self.chassis_id, blade_id=self.blade_id,
-                    blade_intf_distinguished_name=self.\
-                    blade_intf_distinguished_name,
+                    blade_intf_distinguished_name=blade_intf_details[\
+                    const.BLADE_INTF_DN],
                     least_rsvd_blade_dict=self._ucs_inventory.\
                     _get_least_reserved_blade())
-        self.tearDownNetwork(tenant_id, net_id)
+        self.tear_down_network(tenant_id, net_id)
 
-    def tearDownNetworkPortInterface(self, tenant_id, net_id, port_id):
+    def tear_down_network_port_interface(self, tenant_id, net_id, port_id):
         self._cisco_ucs_plugin.unplug_interface(
                                    tenant_id, net_id, port_id,
                                    device_ip=self.device_ip)
-        self.tearDownNetworkPort(tenant_id, net_id, port_id)
+        self.tear_down_network_port(tenant_id, net_id, port_id)
diff --git a/quantum/plugins/cisco/tests/unit/test_vlan_mgr.py b/quantum/plugins/cisco/tests/unit/test_vlan_mgr.py
new file mode 100644 (file)
index 0000000..90e2641
--- /dev/null
@@ -0,0 +1,94 @@
+"""
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+#
+# Copyright 2011 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.
+#
+# @author: Peter Strunk, Cisco Systems, Inc.
+#
+"""
+
+import unittest
+import logging as LOG
+
+from quantum.common import exceptions as exc
+from quantum.plugins.cisco import l2network_plugin_configuration  as conf
+from quantum.plugins.cisco.common import cisco_exceptions as c_exc
+from quantum.plugins.cisco.common import cisco_credentials as creds
+from quantum.plugins.cisco.db import api as db
+from quantum.plugins.cisco.db import l2network_db as cdb
+from quantum.plugins.cisco.segmentation.l2network_vlan_mgr \
+                                import L2NetworkVLANMgr
+
+LOG.basicConfig(level=LOG.WARN)
+LOG.getLogger(__name__)
+
+
+class Test_L2Network_Vlan_Mgr(unittest.TestCase):
+
+    _plugins = {}
+    _inventory = {}
+
+    def setUp(self):
+        db.configure_db({'sql_connection': 'sqlite:///:memory:'})
+        cdb.initialize()
+        creds.Store.initialize()
+        self.tenant_id = "network_admin"
+        self.net_name = "TestNetwork1"
+        self.vlan_name = "TestVlan1"
+        self.vlan_id = 300
+        self.net_id = 100
+        self.vlan_mgr = L2NetworkVLANMgr()
+        self.plugin_key = "quantum.plugins.cisco.ucs.cisco_ucs_plugin" +\
+                          ".UCSVICPlugin"
+
+    def tearDown(self):
+        db.clear_db()
+
+    def test_reserve_segmentation_id(self):
+        LOG.debug("test_reserve_segmentation_id - START")
+        db.network_create(self.tenant_id, self.net_name)
+        vlan_id = self.vlan_mgr.reserve_segmentation_id(self.tenant_id,
+                                                             self.net_name)
+        self.assertEqual(vlan_id, int(conf.VLAN_START))
+        LOG.debug("test_reserve_segmentation_id - END")
+
+    def test_reserve_segmentation_id_NA(self):
+        LOG.debug("test_reserve_segmentation_id - START")
+        db.clear_db()
+        self.assertRaises(c_exc.VlanIDNotAvailable,
+                          self.vlan_mgr.reserve_segmentation_id,
+                          self.tenant_id,
+                          self.net_name)
+        LOG.debug("test_reserve_segmentation_id - END")
+
+    def test_release_segmentation_id(self):
+        LOG.debug("test_release_segmentation_id - START")
+        db.network_create(self.tenant_id, self.net_name)
+        vlan_id = self.vlan_mgr.reserve_segmentation_id(self.tenant_id,
+                                                             self.net_name)
+        cdb.add_vlan_binding(vlan_id, self.vlan_name, self.net_id)
+        release_return = self.vlan_mgr.release_segmentation_id(self.tenant_id,
+                                                                self.net_id)
+        self.assertEqual(release_return, False)
+        LOG.debug("test_release_segmentation_id - END")
+
+    def test_release_segmentation_id_idDNE(self):
+        LOG.debug("test_release_segmentation_idDNE - START")
+        db.network_create(self.tenant_id, self.net_name)
+        self.assertRaises(exc.NetworkNotFound,
+                          self.vlan_mgr.release_segmentation_id,
+                          self.tenant_id,
+                          self.net_id)
+        LOG.debug("test_release_segmentation_idDNE - END")
index 334399abece7af6af77d91f55d40e97d6de2a90a..68cd834c0de04266566c67ab7f768cd9fd218fb2 100644 (file)
@@ -19,7 +19,7 @@
 #
 """
 from copy import deepcopy
-import logging as LOG
+import logging
 
 from quantum.common import exceptions as exc
 from quantum.plugins.cisco.l2device_inventory_base \
@@ -34,8 +34,7 @@ from quantum.plugins.cisco.ucs \
         import cisco_ucs_inventory_configuration as conf
 from quantum.plugins.cisco.ucs import cisco_ucs_network_driver
 
-LOG.basicConfig(level=LOG.WARN)
-LOG.getLogger(__name__)
+LOG = logging.getLogger(__name__)
 
 """
 The _inventory data strcuture contains a nested disctioary:
@@ -208,7 +207,6 @@ class UCSInventory(L2NetworkDeviceInventoryBase):
                         port_binding[const.INSTANCE_ID]
                 intf_data[const.VIF_ID] = \
                         port_binding[const.VIF_ID]
-
         host_name = self._get_host_name(ucsm_ip, chassis_id, blade_id)
         blade_data = {const.BLADE_INTF_DATA: blade_intf_data,
                       const.BLADE_UNRESERVED_INTF_COUNT: unreserved_counter,
@@ -328,7 +326,8 @@ class UCSInventory(L2NetworkDeviceInventoryBase):
                     port_id = port_binding[const.PORTID]
                     udb.update_portbinding(port_id, instance_id=instance_id,
                                            vif_id=vif_id)
-                    db.port_set_attachment_by_id(port_id, vif_id)
+                    db.port_set_attachment_by_id(port_id, vif_id +
+                                                 const.UNPLUGGED)
                     device_name = intf_data[const.BLADE_INTF_RHEL_DEVICE_NAME]
                     profile_name = port_binding[const.PORTPROFILENAME]
                     dynamicnic_details = \
@@ -336,7 +335,7 @@ class UCSInventory(L2NetworkDeviceInventoryBase):
                              const.UCSPROFILE: profile_name}
                     LOG.debug("Found reserved dynamic nic: %s" \
                               "associated with port %s" %
-                              (blade_intf_data[blade_intf], port_id))
+                              (intf_data, port_id))
                     LOG.debug("Returning dynamic nic details: %s" %
                               dynamicnic_details)
                     return dynamicnic_details
@@ -345,9 +344,10 @@ class UCSInventory(L2NetworkDeviceInventoryBase):
                  tenant_id)
         return None
 
-    def _disassociate_vifid_from_port(self, tenant_id, port_id):
+    def _disassociate_vifid_from_port(self, tenant_id, instance_id, vif_id):
         """
-        Return the device name for a reserved interface
+        Disassociate a VIF-ID from a port, this happens when a
+        VM is destroyed
         """
         for ucsm_ip in self._inventory_state.keys():
             ucsm = self._inventory_state[ucsm_ip]
@@ -360,17 +360,24 @@ class UCSInventory(L2NetworkDeviceInventoryBase):
                         if intf_data[const.BLADE_INTF_RESERVATION] == \
                            const.BLADE_INTF_RESERVED and \
                            intf_data[const.TENANTID] == tenant_id and \
-                           intf_data[const.PORTID] == port_id:
-                            vif_id = intf_data[const.VIF_ID]
+                           blade_intf_data[blade_intf][const.INSTANCE_ID] == \
+                           instance_id and \
+                           intf_data[const.VIF_ID][:const.UUID_LENGTH] == \
+                           vif_id:
                             intf_data[const.VIF_ID] = None
                             intf_data[const.INSTANCE_ID] = None
+                            port_binding = udb.get_portbinding_dn(blade_intf)
+                            port_id = port_binding[const.PORTID]
                             udb.update_portbinding(port_id, instance_id=None,
                                                    vif_id=None)
+                            db.port_unset_attachment_by_id(port_id)
                             LOG.debug("Disassociated VIF-ID: %s " \
                                       "from port: %s" \
                                       "in UCS inventory state for blade: %s" %
                                       (vif_id, port_id, intf_data))
-                            return
+                            device_params = {const.DEVICE_IP: [ucsm_ip],
+                                             const.PORTID: port_id}
+                            return device_params
         LOG.warn("Disassociating VIF-ID in UCS inventory failed. " \
                  "Could not find a reserved dynamic nic for tenant: %s" %
                  tenant_id)
@@ -641,9 +648,6 @@ class UCSInventory(L2NetworkDeviceInventoryBase):
         on which a dynamic vnic was reserved for this port
         """
         LOG.debug("unplug_interface() called\n")
-        tenant_id = args[0]
-        port_id = args[2]
-        self._disassociate_vifid_from_port(tenant_id, port_id)
         return self._get_blade_for_port(args)
 
     def schedule_host(self, args):
@@ -666,9 +670,24 @@ class UCSInventory(L2NetworkDeviceInventoryBase):
         vif_id = args[2][const.VIF_ID]
         vif_info = self._get_instance_port(tenant_id, instance_id, vif_id)
         vif_desc = {const.VIF_DESC: vif_info}
+
         LOG.debug("vif_desc is: %s" % vif_desc)
         return vif_desc
 
+    def detach_port(self, args):
+        """
+        Remove the VIF-ID and instance name association
+        with the port
+        """
+        LOG.debug("detach_port() called\n")
+        instance_id = args[1]
+        tenant_id = args[2][const.PROJECT_ID]
+        vif_id = args[2][const.VIF_ID]
+        device_params = self._disassociate_vifid_from_port(tenant_id,
+                                                           instance_id,
+                                                           vif_id)
+        return device_params
+
     def create_multiport(self, args):
         """
         Create multiple ports for a VM
index ba3a125a0195967fdb07cb1be78415e44a1a609c..89775be96653f50093805c2c085d14f3be560ac8 100644 (file)
@@ -24,16 +24,14 @@ Implements a UCSM XML API Client
 """
 
 import httplib
-import logging as LOG
+import logging
 from xml.etree import ElementTree as et
 
 from quantum.plugins.cisco.common import cisco_exceptions as cexc
 from quantum.plugins.cisco.common import cisco_constants as const
 from quantum.plugins.cisco.ucs import cisco_getvif as gvif
 
-
-LOG.basicConfig(level=LOG.WARN)
-LOG.getLogger(const.LOGGER_COMPONENT_NAME)
+LOG = logging.getLogger(__name__)
 
 COOKIE_VALUE = "cookie_placeholder"
 PROFILE_NAME = "profilename_placeholder"
index 6251e85355a7e1eca10ca61f335085d327c3e04b..77e1e4dbeac5396d79bd3300721501379023b495 100644 (file)
@@ -19,7 +19,7 @@
 #
 """
 
-import logging as LOG
+import logging
 
 from quantum.common import exceptions as exc
 from quantum.common import utils
@@ -33,8 +33,7 @@ from quantum.plugins.cisco.db import ucs_db as udb
 from quantum.plugins.cisco.l2device_plugin_base import L2DevicePluginBase
 from quantum.plugins.cisco.ucs import cisco_ucs_configuration as conf
 
-LOG.basicConfig(level=LOG.WARN)
-LOG.getLogger(const.LOGGER_COMPONENT_NAME)
+LOG = logging.getLogger(__name__)
 
 
 class UCSVICPlugin(L2DevicePluginBase):
@@ -255,6 +254,48 @@ class UCSVICPlugin(L2DevicePluginBase):
         return udb.update_portbinding(port_id, vlan_name=new_vlan_name,
                                       vlan_id=conf.DEFAULT_VLAN_ID)
 
+    def create_multiport(self, tenant_id, net_id_list, ports_num, port_id_list,
+                     **kwargs):
+        """
+        Creates a port on the specified Virtual Network.
+        """
+        LOG.debug("UCSVICPlugin:create_multiport() called\n")
+        self._set_ucsm(kwargs[const.DEVICE_IP])
+        qos = None
+        ucs_inventory = kwargs[const.UCS_INVENTORY]
+        least_rsvd_blade_dict = kwargs[const.LEAST_RSVD_BLADE_DICT]
+        chassis_id = least_rsvd_blade_dict[const.LEAST_RSVD_BLADE_CHASSIS]
+        blade_id = least_rsvd_blade_dict[const.LEAST_RSVD_BLADE_ID]
+        blade_data_dict = least_rsvd_blade_dict[const.LEAST_RSVD_BLADE_DATA]
+        port_binding_list = []
+        for port_id, net_id in zip(port_id_list, net_id_list):
+            new_port_profile = \
+                    self._create_port_profile(tenant_id, net_id, port_id,
+                                              conf.DEFAULT_VLAN_NAME,
+                                              conf.DEFAULT_VLAN_ID)
+            profile_name = new_port_profile[const.PROFILE_NAME]
+            rsvd_nic_dict = ucs_inventory.\
+                    reserve_blade_interface(self._ucsm_ip, chassis_id,
+                                            blade_id, blade_data_dict,
+                                            tenant_id, port_id,
+                                            profile_name)
+            port_binding = udb.update_portbinding(port_id,
+                                           portprofile_name=profile_name,
+                                           vlan_name=conf.DEFAULT_VLAN_NAME,
+                                           vlan_id=conf.DEFAULT_VLAN_ID,
+                                           qos=qos)
+            port_binding_list.append(port_binding)
+        return port_binding_list
+
+    def detach_port(self, tenant_id, instance_id, instance_desc, **kwargs):
+        """
+        Remove the association of the VIF with the dynamic vnic
+        """
+        LOG.debug("detach_port() called\n")
+        port_id = kwargs[const.PORTID]
+        kwargs.pop(const.PORTID)
+        return self.unplug_interface(tenant_id, None, port_id, **kwargs)
+
     def _get_profile_name(self, port_id):
         """Returns the port profile name based on the port UUID"""
         profile_name = conf.PROFILE_NAME_PREFIX \
@@ -296,36 +337,3 @@ class UCSVICPlugin(L2DevicePluginBase):
         self._ucsm_ip = ucsm_ip
         self._ucsm_username = cred.Store.getUsername(conf.UCSM_IP_ADDRESS)
         self._ucsm_password = cred.Store.getPassword(conf.UCSM_IP_ADDRESS)
-
-    def create_multiport(self, tenant_id, net_id_list, ports_num, port_id_list,
-                     **kwargs):
-        """
-        Creates a port on the specified Virtual Network.
-        """
-        LOG.debug("UCSVICPlugin:create_multiport() called\n")
-        self._set_ucsm(kwargs[const.DEVICE_IP])
-        qos = None
-        ucs_inventory = kwargs[const.UCS_INVENTORY]
-        least_rsvd_blade_dict = kwargs[const.LEAST_RSVD_BLADE_DICT]
-        chassis_id = least_rsvd_blade_dict[const.LEAST_RSVD_BLADE_CHASSIS]
-        blade_id = least_rsvd_blade_dict[const.LEAST_RSVD_BLADE_ID]
-        blade_data_dict = least_rsvd_blade_dict[const.LEAST_RSVD_BLADE_DATA]
-        port_binding_list = []
-        for port_id, net_id in zip(port_id_list, net_id_list):
-            new_port_profile = \
-                    self._create_port_profile(tenant_id, net_id, port_id,
-                                              conf.DEFAULT_VLAN_NAME,
-                                              conf.DEFAULT_VLAN_ID)
-            profile_name = new_port_profile[const.PROFILE_NAME]
-            rsvd_nic_dict = ucs_inventory.\
-                    reserve_blade_interface(self._ucsm_ip, chassis_id,
-                                            blade_id, blade_data_dict,
-                                            tenant_id, port_id,
-                                            profile_name)
-            port_binding = udb.update_portbinding(port_id,
-                                           portprofile_name=profile_name,
-                                           vlan_name=conf.DEFAULT_VLAN_NAME,
-                                           vlan_id=conf.DEFAULT_VLAN_ID,
-                                           qos=qos)
-            port_binding_list.append(port_binding)
-        return port_binding_list