From a637d67555ecab8cec3cede1ff0b7382ed7e9a25 Mon Sep 17 00:00:00 2001 From: Sumit Naiksatam Date: Sat, 22 Oct 2011 20:03:22 -0700 Subject: [PATCH] New tests are being adding to the Diablo code (Cisco L2-Network plugin), and some fixes in the case where the tests were failing. All changes contained within the Cisco L2-Network plugin and extensions. Change-Id: I696a2aebeb9027f3b0ce0b6673910e02e304673f --- extensions/_novatenant_view.py | 4 + extensions/novatenant.py | 24 ++- quantum/plugins/cisco/README | 34 +++-- .../cisco/common/cisco_configparser.py | 4 - .../plugins/cisco/common/cisco_constants.py | 10 ++ .../plugins/cisco/common/cisco_credentials.py | 4 - .../plugins/cisco/common/cisco_exceptions.py | 8 + quantum/plugins/cisco/common/cisco_utils.py | 5 +- quantum/plugins/cisco/db/l2network_db.py | 2 + quantum/plugins/cisco/db/ucs_db.py | 32 ++++ quantum/plugins/cisco/l2network_plugin.py | 43 ++++-- .../cisco/models/l2network_multi_blade.py | 15 +- .../cisco/models/l2network_single_blade.py | 13 +- .../plugins/cisco/nexus/cisco_nexus_plugin.py | 13 +- quantum/plugins/cisco/nova/vifdirect.py | 42 +++--- .../cisco/segmentation/l2network_vlan_mgr.py | 5 +- .../cisco/tests/unit/test_l2networkApi.py | 142 +++++++++++++----- .../cisco/tests/unit/test_nexus_plugin.py | 112 ++++++++------ .../cisco/tests/unit/test_ucs_plugin.py | 100 ++++++++---- .../plugins/cisco/tests/unit/test_vlan_mgr.py | 94 ++++++++++++ .../plugins/cisco/ucs/cisco_ucs_inventory.py | 47 ++++-- .../cisco/ucs/cisco_ucs_network_driver.py | 6 +- quantum/plugins/cisco/ucs/cisco_ucs_plugin.py | 80 +++++----- 23 files changed, 612 insertions(+), 227 deletions(-) create mode 100644 quantum/plugins/cisco/tests/unit/test_vlan_mgr.py diff --git a/extensions/_novatenant_view.py b/extensions/_novatenant_view.py index b32ff8b64..64a27872a 100644 --- a/extensions/_novatenant_view.py +++ b/extensions/_novatenant_view.py @@ -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) diff --git a/extensions/novatenant.py b/extensions/novatenant.py index 5309ce29e..0460255d4 100644 --- a/extensions/novatenant.py +++ b/extensions/novatenant.py @@ -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)) diff --git a/quantum/plugins/cisco/README b/quantum/plugins/cisco/README index 60c985c66..ea9e78823 100755 --- a/quantum/plugins/cisco/README +++ b/quantum/plugins/cisco/README @@ -205,7 +205,9 @@ password=mySecretPasswordForNexus quantum/plugins/cisco/conf/ucs_inventory.ini file. You can configure multiple UCSMs per deployment, multiple chassis per UCSM, and multiple blades per chassis. Chassis ID and blade ID can be obtained from the UCSM (they will - typically be numbers like 1, 2, 3, etc.) + typically be numbers like 1, 2, 3, etc.). Also make sure that you put the exact + hostname as nova sees it (the host column in the services table of the nova + DB will give you that information). [ucsm-1] ip_address = @@ -241,8 +243,8 @@ host_name = Multi NIC support for VMs ------------------------- As indicated earlier, if your Nova setup has a project with more than one network, -Nova will try to create a vritual network interface (VIF) on the VM for each of those -networks. That implies that, +Nova will try to create a virtual network interface (VIF) on the VM for each of those +networks. That implies - (1) You should create the same number of networks in Quantum as in your Nova project. @@ -325,12 +327,18 @@ for Tenant: demo Note that when using UCS and the 802.1Qbh features, the association of the VIF-ID (also referred to as interface ID) on the VM's NIC with a port will happen automatically when the VM is instantiated. At this point, doing a - show_port will reveal the VIF-ID associated with the port. + show_port will reveal the VIF-ID associated with the port. To indicate that + this VIF-ID is still detached from the network it would eventually be on, you + will see the suffix "(detached)" on the VIF-ID. This indicates that although + the VIF-ID and the port have been associated, the VIF still does not have + connectivity to the network on which the port resides. That connectivity + will be established only after the plug/attach operation is performed (as + described in the next step). # PYTHONPATH=. python quantum/plugins/cisco/client/cli.py show_port demo c4a2bea7-a528-4caf-b16e-80397cd1663a 118ac473-294d-480e-8f6d-425acbbe81ae Logical Port ID: 118ac473-294d-480e-8f6d-425acbbe81ae administrative State: ACTIVE -interface: b73e3585-d074-4379-8dde-931c0fc4db0e +interface: b73e3585-d074-4379-8dde-931c0fc4db0e(detached) on Virtual Network: c4a2bea7-a528-4caf-b16e-80397cd1663a for Tenant: demo @@ -347,17 +355,23 @@ for Tenant: demo 8. Unplug an interface and port from the network - Note: Before unplugging, make a note of the interface ID (you can use the - show_port CLI as before). While the VM, which has a VIF with this interface - ID still exists, you can only plug that same interface back into this port. - So the subsequent plug interface operation on this port will have to make - use of the same interface ID. # PYTHONPATH=. python quantum/plugins/cisco/client/cli.py unplug_iface demo c4a2bea7-a528-4caf-b16e-80397cd1663a 118ac473-294d-480e-8f6d-425acbbe81ae Unplugged interface from Logical Port: 118ac473-294d-480e-8f6d-425acbbe81ae on Virtual Network: c4a2bea7-a528-4caf-b16e-80397cd1663a for Tenant: demo + Note: After unplugging, if you check the details of the port, you will + see the VIF-IF associated with the port (but now suffixed with the state + "detached"). At this point, it is possible to plug the VIF into the network + again making use of the same VIF-ID. In general, once associated, the VIF-ID + cannot be disassociated with the port until the VM is terminated. After the + VM is terminated, the VIF-ID will be automatically disassociated from the + port. To summarize, association and disassociation of the VIF-ID with a port + happens automatically at the time of creating and terminating the VM. The + connectivity of the VIF to the network is controlled by the user via the + plug and unplug operations. + How to test the installation ---------------------------- diff --git a/quantum/plugins/cisco/common/cisco_configparser.py b/quantum/plugins/cisco/common/cisco_configparser.py index 33b2ff127..a96513787 100644 --- a/quantum/plugins/cisco/common/cisco_configparser.py +++ b/quantum/plugins/cisco/common/cisco_configparser.py @@ -19,13 +19,9 @@ # """ -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""" diff --git a/quantum/plugins/cisco/common/cisco_constants.py b/quantum/plugins/cisco/common/cisco_constants.py index 3a99cb9f5..18b31a5a1 100644 --- a/quantum/plugins/cisco/common/cisco_constants.py +++ b/quantum/plugins/cisco/common/cisco_constants.py @@ -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' diff --git a/quantum/plugins/cisco/common/cisco_credentials.py b/quantum/plugins/cisco/common/cisco_credentials.py index 02eab5469..e3f395f98 100644 --- a/quantum/plugins/cisco/common/cisco_credentials.py +++ b/quantum/plugins/cisco/common/cisco_credentials.py @@ -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" diff --git a/quantum/plugins/cisco/common/cisco_exceptions.py b/quantum/plugins/cisco/common/cisco_exceptions.py index 5decb9792..cc775cf46 100644 --- a/quantum/plugins/cisco/common/cisco_exceptions.py +++ b/quantum/plugins/cisco/common/cisco_exceptions.py @@ -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: diff --git a/quantum/plugins/cisco/common/cisco_utils.py b/quantum/plugins/cisco/common/cisco_utils.py index cbfd83727..ba6b07e3b 100644 --- a/quantum/plugins/cisco/common/cisco_utils.py +++ b/quantum/plugins/cisco/common/cisco_utils.py @@ -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): diff --git a/quantum/plugins/cisco/db/l2network_db.py b/quantum/plugins/cisco/db/l2network_db.py index 30a1f5d36..f9b981948 100644 --- a/quantum/plugins/cisco/db/l2network_db.py +++ b/quantum/plugins/cisco/db/l2network_db.py @@ -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() diff --git a/quantum/plugins/cisco/db/ucs_db.py b/quantum/plugins/cisco/db/ucs_db.py index cfe2df27e..617542ffa 100644 --- a/quantum/plugins/cisco/db/ucs_db.py +++ b/quantum/plugins/cisco/db/ucs_db.py @@ -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") diff --git a/quantum/plugins/cisco/l2network_plugin.py b/quantum/plugins/cisco/l2network_plugin.py index dfd05b39c..9b3b60701 100644 --- a/quantum/plugins/cisco/l2network_plugin.py +++ b/quantum/plugins/cisco/l2network_plugin.py @@ -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. diff --git a/quantum/plugins/cisco/models/l2network_multi_blade.py b/quantum/plugins/cisco/models/l2network_multi_blade.py index a3967025a..539f360ee 100644 --- a/quantum/plugins/cisco/models/l2network_multi_blade.py +++ b/quantum/plugins/cisco/models/l2network_multi_blade.py @@ -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(), diff --git a/quantum/plugins/cisco/models/l2network_single_blade.py b/quantum/plugins/cisco/models/l2network_single_blade.py index 5636c0665..4184edb4b 100644 --- a/quantum/plugins/cisco/models/l2network_single_blade.py +++ b/quantum/plugins/cisco/models/l2network_single_blade.py @@ -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(), diff --git a/quantum/plugins/cisco/nexus/cisco_nexus_plugin.py b/quantum/plugins/cisco/nexus/cisco_nexus_plugin.py index dd93cf10e..6c752832e 100644 --- a/quantum/plugins/cisco/nexus/cisco_nexus_plugin.py +++ b/quantum/plugins/cisco/nexus/cisco_nexus_plugin.py @@ -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} diff --git a/quantum/plugins/cisco/nova/vifdirect.py b/quantum/plugins/cisco/nova/vifdirect.py index 015c9aceb..cfc891298 100644 --- a/quantum/plugins/cisco/nova/vifdirect.py +++ b/quantum/plugins/cisco/nova/vifdirect.py @@ -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) diff --git a/quantum/plugins/cisco/segmentation/l2network_vlan_mgr.py b/quantum/plugins/cisco/segmentation/l2network_vlan_mgr.py index f361980a4..c60a1afd9 100644 --- a/quantum/plugins/cisco/segmentation/l2network_vlan_mgr.py +++ b/quantum/plugins/cisco/segmentation/l2network_vlan_mgr.py @@ -19,15 +19,14 @@ # """ -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): diff --git a/quantum/plugins/cisco/tests/unit/test_l2networkApi.py b/quantum/plugins/cisco/tests/unit/test_l2networkApi.py index 7b4bfac73..92c0aed1d 100644 --- a/quantum/plugins/cisco/tests/unit/test_l2networkApi.py +++ b/quantum/plugins/cisco/tests/unit/test_l2networkApi.py @@ -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): diff --git a/quantum/plugins/cisco/tests/unit/test_nexus_plugin.py b/quantum/plugins/cisco/tests/unit/test_nexus_plugin.py index 65711e7c0..bb8f4b2bd 100644 --- a/quantum/plugins/cisco/tests/unit/test_nexus_plugin.py +++ b/quantum/plugins/cisco/tests/unit/test_nexus_plugin.py @@ -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() diff --git a/quantum/plugins/cisco/tests/unit/test_ucs_plugin.py b/quantum/plugins/cisco/tests/unit/test_ucs_plugin.py index 6c1e54a70..b8fa34de6 100644 --- a/quantum/plugins/cisco/tests/unit/test_ucs_plugin.py +++ b/quantum/plugins/cisco/tests/unit/test_ucs_plugin.py @@ -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 index 000000000..90e2641ce --- /dev/null +++ b/quantum/plugins/cisco/tests/unit/test_vlan_mgr.py @@ -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") diff --git a/quantum/plugins/cisco/ucs/cisco_ucs_inventory.py b/quantum/plugins/cisco/ucs/cisco_ucs_inventory.py index 334399abe..68cd834c0 100644 --- a/quantum/plugins/cisco/ucs/cisco_ucs_inventory.py +++ b/quantum/plugins/cisco/ucs/cisco_ucs_inventory.py @@ -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 diff --git a/quantum/plugins/cisco/ucs/cisco_ucs_network_driver.py b/quantum/plugins/cisco/ucs/cisco_ucs_network_driver.py index ba3a125a0..89775be96 100644 --- a/quantum/plugins/cisco/ucs/cisco_ucs_network_driver.py +++ b/quantum/plugins/cisco/ucs/cisco_ucs_network_driver.py @@ -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" diff --git a/quantum/plugins/cisco/ucs/cisco_ucs_plugin.py b/quantum/plugins/cisco/ucs/cisco_ucs_plugin.py index 6251e8535..77e1e4dbe 100644 --- a/quantum/plugins/cisco/ucs/cisco_ucs_plugin.py +++ b/quantum/plugins/cisco/ucs/cisco_ucs_plugin.py @@ -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 -- 2.45.2