From d047001964401cec3e64396bfd73f73901cdc7c5 Mon Sep 17 00:00:00 2001 From: Sumit Naiksatam Date: Fri, 19 Aug 2011 20:07:28 -0700 Subject: [PATCH 01/39] Initial commit with lots of changes. --- .../plugins/cisco/common/cisco_constants.py | 12 + .../plugins/cisco/conf/l2network_plugin.ini | 9 +- quantum/plugins/cisco/conf/ucs_inventory.ini | 24 ++ quantum/plugins/cisco/l2network_plugin.py | 25 +- .../cisco/l2network_segmentation_base.py | 75 ++++ quantum/plugins/cisco/models/__init__.py | 20 + .../cisco/models/l2network_multi_blade.py | 170 +++++++++ .../l2network_single_blade.py} | 18 +- .../plugins/cisco/segmentation/__init__.py | 20 + .../cisco/segmentation/l2network_vlan_mgr.py | 47 +++ .../cisco/ucs/cisco_ucs_configuration.py | 7 + .../plugins/cisco/ucs/cisco_ucs_inventory.py | 361 ++++++++++++++++++ .../cisco/ucs/cisco_ucs_network_driver.py | 127 +++++- quantum/plugins/cisco/ucs/cisco_ucs_plugin.py | 49 ++- 14 files changed, 928 insertions(+), 36 deletions(-) create mode 100644 quantum/plugins/cisco/conf/ucs_inventory.ini create mode 100644 quantum/plugins/cisco/l2network_segmentation_base.py create mode 100644 quantum/plugins/cisco/models/__init__.py create mode 100644 quantum/plugins/cisco/models/l2network_multi_blade.py rename quantum/plugins/cisco/{l2network_model.py => models/l2network_single_blade.py} (87%) create mode 100644 quantum/plugins/cisco/segmentation/__init__.py create mode 100644 quantum/plugins/cisco/segmentation/l2network_vlan_mgr.py create mode 100644 quantum/plugins/cisco/ucs/cisco_ucs_inventory.py diff --git a/quantum/plugins/cisco/common/cisco_constants.py b/quantum/plugins/cisco/common/cisco_constants.py index 67ba05d581..02eb2d4311 100644 --- a/quantum/plugins/cisco/common/cisco_constants.py +++ b/quantum/plugins/cisco/common/cisco_constants.py @@ -128,5 +128,17 @@ VIF_DESC = 'vif_desc' DEVICENAME = 'device' UCSPROFILE = 'portprofile' +IP_ADDRESS = 'ip_address' +CHASSIS_ID = 'chassis_id' +BLADE_ID = 'blade_id' +HOST_NAME = 'host_name' + +INSTANCE_ID = 'instance_id' + +UCS_INVENTORY = 'ucs_inventory' +LEAST_RSVD_BLADE_DICT = 'least_rsvd_blade_dict' + +UCSM_IP = 'ucsm_ip_address' + MAX_CREDENTIALS = 65568 MAX_QOS_LEVELS = 1024 diff --git a/quantum/plugins/cisco/conf/l2network_plugin.ini b/quantum/plugins/cisco/conf/l2network_plugin.ini index 3a740a9713..494279e790 100644 --- a/quantum/plugins/cisco/conf/l2network_plugin.ini +++ b/quantum/plugins/cisco/conf/l2network_plugin.ini @@ -1,6 +1,6 @@ [VLANS] -vlan_start= -vlan_end= +vlan_start=100 +vlan_end=3000 vlan_name_prefix=q- [PORTS] @@ -13,4 +13,7 @@ max_port_profiles=65568 max_networks=65568 [MODEL] -model_class=quantum.plugins.cisco.l2network_model.L2NetworkModel +model_class=quantum.plugins.cisco.models.l2network_single_blade.L2NetworkSinlgeBlade + +[SEGMENTATION] +manager_class=quantum.plugins.cisco.segmentation.l2network_vlan_mgr.L2NetworkVLANMgr diff --git a/quantum/plugins/cisco/conf/ucs_inventory.ini b/quantum/plugins/cisco/conf/ucs_inventory.ini new file mode 100644 index 0000000000..889609adc8 --- /dev/null +++ b/quantum/plugins/cisco/conf/ucs_inventory.ini @@ -0,0 +1,24 @@ +[ucsm-1] +ip_address = +[[chassis-1]] +chassis_id = +[[[blade-1]]] +blade_id = +host_name = +[[[blade-2]]] +blade_id = +host_name = +[[[blade-3]]] +blade_id = +host_name = + +[ucsm-2] +ip_address = +[[chassis-1]] +chassis_id = +[[[blade-1]]] +blade_id = +host_name = +[[[blade-2]]] +blade_id = +host_name = diff --git a/quantum/plugins/cisco/l2network_plugin.py b/quantum/plugins/cisco/l2network_plugin.py index 29fc354242..a4b30953e7 100644 --- a/quantum/plugins/cisco/l2network_plugin.py +++ b/quantum/plugins/cisco/l2network_plugin.py @@ -47,6 +47,7 @@ class L2Network(QuantumPluginBase): def __init__(self): self._vlan_counter = int(conf.VLAN_START) - 1 self._model = utils.import_object(conf.MODEL_CLASS) + self._vlan_mgr = utils.import_object(conf.MANAGER_CLASS) cdb.initialize() # TODO (Sumit): The following should move to the segmentation module cdb.create_vlanids() @@ -442,41 +443,35 @@ class L2Network(QuantumPluginBase): def get_host(self, tenant_id, instance_id, instance_desc): """Provides the hostname on which a dynamic vnic is reserved""" LOG.debug("get_host() called\n") - host_list = {const.HOST_LIST: {const.HOST_1: platform.node()}} - return host_list + return self._invoke_device_plugins(self._func_name(), [tenant_id, + instance_id, + instance_desc]) def get_instance_port(self, tenant_id, instance_id, instance_desc): """ Get the portprofile name and the device namei for the dynamic vnic """ LOG.debug("get_instance_port() called\n") - vif_desc = {const.VIF_DESC: - {const.DEVICENAME: "eth2", const.UCSPROFILE: "default"}} - return vif_desc + return self._invoke_device_plugins(self._func_name(), [tenant_id, + instance_id, + instance_desc]) """ Private functions """ def _invoke_device_plugins(self, function_name, args): """ - All device-specific calls are delegate to the model + All device-specific calls are delegated to the model """ getattr(self._model, function_name)(args) def _get_vlan_for_tenant(self, tenant_id, net_name): """Get vlan ID""" - # TODO (Sumit): - # The VLAN ID for a tenant might need to be obtained from - # somewhere (from Donabe/Melange?) - # Also need to make sure that the VLAN ID is not being used already - # Currently, just a wrap-around counter ranging from VLAN_START to - # VLAN_END - return cdb.reserve_vlanid() + return self._vlan_mgr.reserve_segmentation_id(tenant_id, net_name) def _release_vlan_for_tenant(self, tenant_id, net_id): """Relase VLAN""" - vlan_binding = cdb.get_vlan_binding(net_id) - return cdb.release_vlanid(vlan_binding[const.VLANID]) + return self._vlan_mgr.release_segmentation_id(tenant_id, net_id) def _get_vlan_name(self, net_id, vlan): """Getting the vlan name from the tenant and vlan""" diff --git a/quantum/plugins/cisco/l2network_segmentation_base.py b/quantum/plugins/cisco/l2network_segmentation_base.py new file mode 100644 index 0000000000..d7b4378b8b --- /dev/null +++ b/quantum/plugins/cisco/l2network_segmentation_base.py @@ -0,0 +1,75 @@ +""" +# 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: Sumit Naiksatam, Cisco Systems, Inc. +# +""" + +import inspect +from abc import ABCMeta, abstractmethod + + +class L2NetworkSegmentationMgrBase(object): + """ + Base class for L2 Network Segmentation Manager + """ + + __metaclass__ = ABCMeta + + @abstractmethod + def reserve_segmentation_id(self, tenant_id, net_name, **kwargs): + """ + :returns: + :raises: + """ + pass + + @abstractmethod + def release_segmentation_id(self, tenant_id, net_id, **kwargs): + """ + :returns: + :raises: + """ + pass + + @classmethod + def __subclasshook__(cls, klass): + """ + The __subclasshook__ method is a class method + that will be called everytime a class is tested + using issubclass(klass, Plugin). + In that case, it will check that every method + marked with the abstractmethod decorator is + provided by the plugin class. + """ + if cls is L2NetworkSegementationMgrBase: + for method in cls.__abstractmethods__: + method_ok = False + for base in klass.__mro__: + if method in base.__dict__: + fn_obj = base.__dict__[method] + if inspect.isfunction(fn_obj): + abstract_fn_obj = cls.__dict__[method] + arg_count = fn_obj.func_code.co_argcount + expected_arg_count = \ + abstract_fn_obj.func_code.co_argcount + method_ok = arg_count == expected_arg_count + if method_ok: + continue + return NotImplemented + return True + return NotImplemented diff --git a/quantum/plugins/cisco/models/__init__.py b/quantum/plugins/cisco/models/__init__.py new file mode 100644 index 0000000000..09b3fab896 --- /dev/null +++ b/quantum/plugins/cisco/models/__init__.py @@ -0,0 +1,20 @@ +""" +# 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: Sumit Naiksatam, Cisco Systems, Inc. +# +""" diff --git a/quantum/plugins/cisco/models/l2network_multi_blade.py b/quantum/plugins/cisco/models/l2network_multi_blade.py new file mode 100644 index 0000000000..c5ba157d29 --- /dev/null +++ b/quantum/plugins/cisco/models/l2network_multi_blade.py @@ -0,0 +1,170 @@ +""" +# 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: Sumit Naiksatam, Cisco Systems, Inc. +# +""" + +import inspect +import logging as LOG + +from quantum.common import utils +from quantum.plugins.cisco.l2network_model_base import L2NetworkModelBase +from quantum.plugins.cisco import l2network_plugin_configuration as conf +from quantum.plugins.cisco.common import cisco_constants as const +from quantum.plugins.cisco.ucs import cisco_ucs_inventory as ucsinv + +LOG.basicConfig(level=LOG.WARN) +LOG.getLogger(const.LOGGER_COMPONENT_NAME) + + +class L2NetworkMultiBlade(L2NetworkModelBase): + """ + Implements the L2NetworkModelBase + This implementation works with UCS and Nexus plugin for the + following topology: + One or more UCSM (each with one or more chasses connected) + All UCSM connected to a single Nexus Switch + """ + _plugins = {} + + def __init__(self): + for key in conf.PLUGINS[const.PLUGINS].keys(): + self._plugins[key] = utils.import_object( + conf.PLUGINS[const.PLUGINS][key]) + LOG.debug("Loaded device plugin %s\n" % \ + conf.PLUGINS[const.PLUGINS][key]) + + self._ucs_inventory = ucsinv.UCSInventory() + + def _func_name(self, offset=0): + """Get the name of the calling function""" + return inspect.stack()[1 + offset][3] + + def _invoke_all_device_plugins(self, function_name, args, kwargs): + """Invoke all device plugins for this model implementation""" + for plugin_obj_ref in self._plugins.values(): + getattr(plugin_obj_ref, function_name)(*args, **kwargs) + + def _invoke_ucs_plugin(self, function_name, args, kwargs): + """Invoke only the UCS plugin""" + if const.UCS_PLUGIN in self._plugins.keys(): + getattr(self._plugins[const.UCS_PLUGIN], + function_name)(*args, **kwargs) + + def _invoke_ucs_plugin_per_device(self, function_name, args): + """Invoke only UCS plugin for all the UCSMs in the system""" + ucsm_ips = self._ucs_inventory.get_all_ucsms() + for ucsm_ip in ucsm_ips: + device_params = {const.DEVICE_IP: ucsm_ip} + self._invoke_ucs_plugin(function_name, args, device_params) + + def _invoke_nexus_plugin(self, function_name, args, kwargs): + """Invoke only the Nexus plugin""" + if const.NEXUS_PLUGIN in self._plugins.keys(): + getattr(self._plugins[const.NEXUS_PLUGIN], + function_name)(*args, **kwargs) + + def _invoke_nexus_plugin_per_device(self, function_name, args): + """Invoke only the nexus plugin for all the switches in the system""" + device_params = {const.DEVICE_IP: ""} + self._invoke_nexus_plugin(self._func_name(), args, device_params) + + def get_all_networks(self, args): + """Not implemented for this model""" + pass + + def create_network(self, args): + """Support for the Quantum core API call""" + self._invoke_ucs_plugin_per_device(self._func_name(), args) + self._invoke_nexus_plugin_per_device(self._func_name(), args) + + def delete_network(self, args): + """Support for the Quantum core API call""" + self._invoke_ucs_plugin_per_device(self._func_name(), args) + self._invoke_nexus_plugin_per_device(self._func_name(), args) + + def get_network_details(self, args): + """Not implemented for this model""" + pass + + def rename_network(self, args): + """Support for the Quantum core API call""" + self._invoke_ucs_plugin_per_device(self._func_name(), args) + self._invoke_nexus_plugin_per_device(self._func_name(), args) + + def get_all_ports(self, args): + """Not implemented for this model""" + pass + + def create_port(self, args): + """Support for the Quantum core API call""" + least_reserved_blade_dict = \ + self._ucs_inventory.get_least_reserved_blade() + ucsm_ip = least_reserved_blade_dict[const.LEAST_RSVD_BLADE_UCSM] + device_params = {const.DEVICE_IP: ucsm_ip, + const.UCS_INVENTORY: self._ucs_inventory, + const.LEAST_RSVD_BLADE_DICT:\ + least_reserved_blade_dict} + self._invoke_ucs_plugin(self._func_name(), args, device_params) + + def delete_port(self, args): + """Support for the Quantum core API call""" + rsvd_info = \ + self._ucs_inventory.get_rsvd_blade_intf_by_port(args[0], + args[2]) + device_params = \ + {const.DEVICE_IP: rsvd_info[const.UCSM_IP], + const.UCS_INVENTORY: self._ucs_inventory, + const.CHASSIS_ID: rsvd_info[const.const.CHASSIS_ID], + const.BLADE_ID: rsvd_info[const.const.BLADE_ID], + const.BLADE_INTF_DN: rsvd_info[const.BLADE_INTF_DN]} + self._invoke_ucs_plugin(self._func_name(), args, device_params) + + def update_port(self, args): + """Not implemented for this model""" + pass + + def get_port_details(self, args): + """Not implemented for this model""" + pass + + def plug_interface(self, args): + """Support for the Quantum core API call""" + device_params = {const.DEVICE_IP: ""} + self._invoke_ucs_plugin(self._func_name(), args, device_params) + + def unplug_interface(self, args): + """Support for the Quantum core API call""" + device_params = {const.DEVICE_IP: ""} + self._invoke_ucs_plugin(self._func_name(), args, device_params) + + def get_host(self, args): + """Provides the hostname on which a dynamic vnic is reserved""" + LOG.debug("get_host() called\n") + host_list = {const.HOST_LIST: {const.HOST_1: platform.node()}} + return host_list + + def get_instance_port(self, args): + """ + Get the portprofile name and the device namei for the dynamic vnic + """ + LOG.debug("get_instance_port() called\n") + vif_desc = {const.VIF_DESC: + {const.DEVICENAME: "eth2", const.UCSPROFILE: "default"}} + return vif_desc + diff --git a/quantum/plugins/cisco/l2network_model.py b/quantum/plugins/cisco/models/l2network_single_blade.py similarity index 87% rename from quantum/plugins/cisco/l2network_model.py rename to quantum/plugins/cisco/models/l2network_single_blade.py index cdffa594e4..286f5c7dde 100644 --- a/quantum/plugins/cisco/l2network_model.py +++ b/quantum/plugins/cisco/models/l2network_single_blade.py @@ -31,7 +31,7 @@ LOG.basicConfig(level=LOG.WARN) LOG.getLogger(const.LOGGER_COMPONENT_NAME) -class L2NetworkModel(L2NetworkModelBase): +class L2NetworkSinlgeBlade(L2NetworkModelBase): """ Implements the L2NetworkModelBase This implementation works with UCS and Nexus plugin, @@ -121,3 +121,19 @@ class L2NetworkModel(L2NetworkModelBase): """Support for the Quantum core API call""" device_params = {const.DEVICE_IP: ""} self._invoke_ucs_plugin(self._func_name(), args, device_params) + + def get_host(self, args): + """Provides the hostname on which a dynamic vnic is reserved""" + LOG.debug("get_host() called\n") + host_list = {const.HOST_LIST: {const.HOST_1: platform.node()}} + return host_list + + def get_instance_port(self, args): + """ + Get the portprofile name and the device namei for the dynamic vnic + """ + LOG.debug("get_instance_port() called\n") + vif_desc = {const.VIF_DESC: + {const.DEVICENAME: "eth2", const.UCSPROFILE: "default"}} + return vif_desc + diff --git a/quantum/plugins/cisco/segmentation/__init__.py b/quantum/plugins/cisco/segmentation/__init__.py new file mode 100644 index 0000000000..09b3fab896 --- /dev/null +++ b/quantum/plugins/cisco/segmentation/__init__.py @@ -0,0 +1,20 @@ +""" +# 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: Sumit Naiksatam, Cisco Systems, Inc. +# +""" diff --git a/quantum/plugins/cisco/segmentation/l2network_vlan_mgr.py b/quantum/plugins/cisco/segmentation/l2network_vlan_mgr.py new file mode 100644 index 0000000000..427ab690f6 --- /dev/null +++ b/quantum/plugins/cisco/segmentation/l2network_vlan_mgr.py @@ -0,0 +1,47 @@ +""" +# 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: Sumit Naiksatam, Cisco Systems, Inc. +# +""" + +import logging as LOG + +from quantum.common import utils +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) + +class L2NetworkVLANMgr(L2NetworkSegmentationMgrBase): + """ + VLAN Manager which gets VLAN ID from DB + """ + + def reserve_segmentation_id(self, tenant_id, net_name, **kwargs): + """Get an available VLAN ID""" + return cdb.reserve_vlanid() + + + def release_segmentation_id(self, tenant_id, net_id, **kwargs): + """Release the ID""" + vlan_binding = cdb.get_vlan_binding(net_id) + return cdb.release_vlanid(vlan_binding[const.VLANID]) + diff --git a/quantum/plugins/cisco/ucs/cisco_ucs_configuration.py b/quantum/plugins/cisco/ucs/cisco_ucs_configuration.py index 8c33481542..a4fbec42b1 100644 --- a/quantum/plugins/cisco/ucs/cisco_ucs_configuration.py +++ b/quantum/plugins/cisco/ucs/cisco_ucs_configuration.py @@ -37,3 +37,10 @@ PROFILE_NAME_PREFIX = SECTION['profile_name_prefix'] SECTION = CP['DRIVER'] UCSM_DRIVER = SECTION['name'] + +CONF_FILE = "../conf/ucs_inventory.ini" + +CP = confp.CiscoConfigParser(os.path.dirname(os.path.realpath(__file__)) \ + + "/" + CONF_FILE) + +INVENTORY = CP.walk(CP.dummy) diff --git a/quantum/plugins/cisco/ucs/cisco_ucs_inventory.py b/quantum/plugins/cisco/ucs/cisco_ucs_inventory.py new file mode 100644 index 0000000000..a272c0ae00 --- /dev/null +++ b/quantum/plugins/cisco/ucs/cisco_ucs_inventory.py @@ -0,0 +1,361 @@ +# 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: Sumit Naiksatam, Cisco Systems, Inc. +# + +import logging as LOG + +from quantum.common import exceptions as exc +from quantum.plugins.cisco.common import cisco_constants as const +from quantum.plugins.cisco.common import cisco_credentials as cred +from quantum.plugins.cisco.common import cisco_exceptions as cexc +from quantum.plugins.cisco.common import cisco_utils as cutil +from quantum.plugins.cisco.ucs import cisco_ucs_configuration as conf +from quantum.plugins.cisco.ucs import cisco_ucs_network_driver + +LOG.basicConfig(level=LOG.WARN) +LOG.getLogger(const.LOGGER_COMPONENT_NAME) + +""" +The _inventory data strcuture contains a nested disctioary: + {"UCSM_IP: {"Chassis-ID": [Balde-ID, Blade-ID], + "Chassis-ID": [Blade-ID, Blade-ID, Blade-ID]]}, + "UCSM_IP: {"Chassis-ID": [Balde-ID]} + } +""" + +class UCSInventory(object): + + _inventory = {} + _host_names = {} + _inventory_state = {} + + def __init__(self): + self._client = cisco_ucs_network_driver.CiscoUCSMDriver() + self._load_inventory() + + def _load_inventory(self): + """Load the inventory from a config file""" + inventory = conf.INVENTORY + for ucsm in inventory.keys(): + ucsm_ip = inventory[ucsm][const.IP_ADDRESS] + inventory[ucsm].pop(const.IP_ADDRESS) + chassis_dict = {} + for chassis in inventory[ucsm].keys(): + chassis_id = inventory[ucsm][chassis][const.CHASSIS_ID] + inventory[ucsm][chassis].pop(const.CHASSIS_ID) + blade_list = [] + for blade in inventory[ucsm][chassis].keys(): + blade_id = \ + inventory[ucsm][chassis][blade][const.BLADE_ID] + host_name = \ + inventory[ucsm][chassis][blade][const.HOST_NAME] + host_key = ucsm_ip + "-" + chassis_id + "-" + blade_id + self._host_names[host_key] = host_name + blade_list.append(blade_id) + chassis_dict[chassis_id] = blade_list + self._inventory[ucsm_ip] = chassis_dict + + def _get_host_name(self, ucsm_ip, chassis_id, blade_id): + """Get the hostname based on the blade info""" + host_key = ucsm_ip + "-" + chassis_id + "-" + blade_id + return self._host_names[host_key] + + def _get_blade_state(self, chassis_id, blade_id, ucsm_ip, ucsm_username, + ucsm_password): + """Get the blade state""" + blade_intf_data = self._client.get_blade_data(chassis_id, blade_id, + ucsm_ip, ucsm_username, + ucsm_password) + unreserved_counter = 0 + + for blade_intf in blade_intf_data.keys(): + if (blade_intf_data[blade_intf][const.BLADE_INTF_LINK_STATE] == \ + const.BLADE_INTF_STATE_UNALLOCATED or \ + blade_intf_data[blade_intf][const.BLADE_INTF_LINK_STATE] == \ + const.BLADE_INTF_STATE_UNKNOWN) and \ + blade_intf_data[blade_intf][const.BLADE_INTF_OPER_STATE] == \ + const.BLADE_INTF_STATE_UNKNOWN: + blade_intf_data[blade_intf][const.BLADE_INTF_RESERVATION] = \ + const.BLADE_INTF_UNRESERVED + unreserved_counter += 1 + else: + blade_intf_data[blade_intf][const.BLADE_INTF_RESERVATION] = \ + const.BLADE_INTF_RESERVED + + blade_data = {const.BLADE_INTF_DATA: blade_intf_data, + const.BLADE_UNRESERVED_INTF_COUNT: unreserved_counter} + return blade_data + + def get_all_ucsms(self): + return self._inventory.keys() + + def reload_inventory(self): + """Reload the inventory from a conf file""" + self._load_inventory() + pass + + def build_inventory_state(self): + """Populate the state of all the blades""" + for ucsm_ip in self._inventory.keys(): + self._inventory_state[ucsm_ip] = {ucsm_ip: {}} + ucsm_username = cred.Store.getUsername(ucsm_ip) + ucsm_password = cred.Store.getPassword(ucsm_ip) + chasses_state = {} + self._inventory_state[ucsm_ip] = chasses_state + ucsm = self._inventory[ucsm_ip] + for chassis_id in ucsm.keys(): + blades_dict = {} + chasses_state[chassis_id] = blades_dict + for blade_id in ucsm[chassis_id]: + blade_data = self._get_blade_state(chassis_id, blade_id, + ucsm_ip, ucsm_username, + ucsm_password) + blades_dict[blade_id] = blade_data + + return True + + def get_least_reserved_blade(self): + """Return the blade with least number of dynamic nics reserved""" + unreserved_interface_count = 0 + least_reserved_blade_ucsm = None + least_reserved_blade_chassis = None + least_reserved_blade_id = None + least_reserved_blade_data = None + + for ucsm_ip in self._inventory_state.keys(): + ucsm = self._inventory_state[ucsm_ip] + for chassis_id in ucsm.keys(): + for blade_id in ucsm[chassis_id]: + blade_data = ucsm[chassis_id][blade_id] + if blade_data[const.BLADE_UNRESERVED_INTF_COUNT] > \ + unreserved_interface_count: + unreserved_interface_count = \ + blade_data[const.BLADE_UNRESERVED_INTF_COUNT] + least_reserved_blade_ucsm = ucsm_ip + least_reserved_blade_chassis = chassis_id + least_reserved_blade_id = blade_id + least_reserved_blade_data = blade_data + + if unreserved_interface_count == 0: + return False + + least_reserved_blade_dict = \ + {const.LEAST_RSVD_BLADE_UCSM: least_reserved_blade_ucsm, + const.LEAST_RSVD_BLADE_CHASSIS: least_reserved_blade_chassis, + const.LEAST_RSVD_BLADE_ID: least_reserved_blade_id, + const.LEAST_RSVD_BLADE_DATA: least_reserved_blade_data} + return least_reserved_blade_dict + + def reserve_blade_interface(self, ucsm_ip, chassis_id, blade_id, + blade_data_dict, tenant_id, port_id, + portprofile_name): + """Reserve an interface on a blade""" + ucsm_username = cred.Store.getUsername(ucsm_ip) + ucsm_password = cred.Store.getPassword(ucsm_ip) + """ + We are first getting the updated blade interface state + """ + blade_data = self._get_blade_state(chassis_id, blade_id, ucsm_ip, + ucsm_username, ucsm_password) + blade_intf_data = blade_data[const.BLADE_INTF_DATA] + old_blade_intf_data = blade_data_dict[const.BLADE_INTF_DATA] + + """ + We will now copy the older blade interface reservation state + """ + for blade_intf in blade_intf_data.keys(): + blade_intf_data[blade_intf][const.BLADE_INTF_RESERVATION] = \ + old_blade_intf_data[blade_intf]\ + [const.BLADE_INTF_RESERVATION] + + blade_data[const.BLADE_UNRESERVED_INTF_COUNT] = \ + blade_data_dict[const.BLADE_UNRESERVED_INTF_COUNT] + """ + Now we will reserve an interface if its available + """ + for blade_intf in blade_intf_data.keys(): + if blade_intf_data[blade_intf][const.BLADE_INTF_RESERVATION] == \ + const.BLADE_INTF_UNRESERVED: + blade_intf_data[blade_intf][const.BLADE_INTF_RESERVATION] = \ + const.BLADE_INTF_RESERVED + blade_intf_data[blade_intf][const.TENANTID] = tenant_id + blade_intf_data[blade_intf][const.PORTID] = port_id + blade_intf_data[blade_intf][const.PROFILEID] = portprofile_name + blade_intf_data[blade_intf][const.INSTANCE_ID] = None + dev_eth_name = blade_intf_data[blade_intf] \ + [const.BLADE_INTF_RHEL_DEVICE_NAME] + """ + We are replacing the older blade interface state with new + """ + self._inventory_state[ucsm_ip][chassis_id][blade_id] \ + [const.BLADE_INTF_DATA] = blade_intf_data + self._inventory_state[ucsm_ip][chassis_id][blade_id] \ + [const.BLADE_UNRESERVED_INTF_COUNT] -= 1 + host_name = self._get_host_name(ucsm_ip, chassis_id, + blade_id) + reserved_nic_dict = {const.RESERVED_NIC_HOSTNAME: host_name, + const.RESERVED_NIC_NAME: dev_eth_name, + const.BLADE_INTF_DN: blade_intf} + LOG.debug("Reserved blade interface: %s\n" % reserved_nic_dict) + return reserved_nic_dict + + return False + + def unreserve_blade_interface(self, ucsm_ip, chassis_id, blade_id, + interface_dn): + """Unreserve a previously reserved interface on a blade""" + ucsm_username = cred.Store.getUsername(ucsm_ip) + ucsm_password = cred.Store.getPassword(ucsm_ip) + self._inventory_state[ucsm_ip][chassis_id][blade_id]\ + [const.BLADE_INTF_DATA] \ + [interface_dn][const.BLADE_INTF_RESERVATION] = \ + const.BLADE_INTF_UNRESERVED + self._inventory_state[ucsm_ip][chassis_id][blade_id] \ + [const.BLADE_UNRESERVED_INTF_COUNT] += 1 + LOG.debug("Unreserved blade interface %s\n" % interface_dn) + + def get_rsvd_blade_intf_by_port(self, tenant_id, port_id): + """ + Lookup a reserved blade interface based on tenant_id and port_id + and return the blade interface info + """ + for ucsm_ip in self._inventory_state.keys(): + ucsm = self._inventory_state[ucsm_ip] + for chassis_id in ucsm.keys(): + for blade_id in ucsm[chassis_id]: + blade_data = ucsm[chassis_id][blade_id] + blade_intf_data = blade_data[const.BLADE_INTF_DATA] + for blade_intf in blade_intf_data.keys(): + if blade_intf_data[blade_intf]\ + [const.BLADE_INTF_RESERVATION] == \ + const.BLADE_INTF_RESERVED and \ + blade_intf_data[blade_intf]\ + [const.TENANTID] == tenant_id and \ + blade_intf_data[blade_intf]\ + [const.PORTID] == port_id: + interface_dn = blade_intf_data[blade_intf]\ + [const.BLADE_INTF_DN] + blade_intf_info = {const.UCSM_IP: ucsm_ip, + const.CHASSIS_ID: chassis_id, + const.BLADE_ID: blade_id, + const.BLADE_INTF_DN: + interface_dn} + return blade_intf_info + return None + + def get_host_name(self, tenant_id, instance_id): + """ + Return the hostname of the blade with a reserved instance + for this tenant + """ + for ucsm_ip in self._inventory_state.keys(): + ucsm = self._inventory_state[ucsm_ip] + for chassis_id in ucsm.keys(): + for blade_id in ucsm[chassis_id]: + blade_data = ucsm[chassis_id][blade_id] + blade_intf_data = blade_data[const.BLADE_INTF_DATA] + for blade_intf in blade_intf_data.keys(): + if blade_intf_data[blade_intf]\ + [const.BLADE_INTF_RESERVATION] == \ + const.BLADE_INTF_RESERVED and \ + blade_intf_data[blade_intf]\ + [const.TENANTID] == tenant_id and \ + blade_intf_data[blade_intf]\ + [const.INSTANCE_ID] == None: + blade_intf_data[blade_intf]\ + [const.INSTANCE_ID] = instance_id + host_name = self._get_host_name(ucsm_ip, + chassis_id, + blade_id) + return host_name + return None + + def get_instance_port(self, tenant_id, instance_id): + """ + Return the device name for a reserved interface + """ + for ucsm_ip in self._inventory_state.keys(): + ucsm = self._inventory_state[ucsm_ip] + for chassis_id in ucsm.keys(): + for blade_id in ucsm[chassis_id]: + blade_data = ucsm[chassis_id][blade_id] + blade_intf_data = blade_data[const.BLADE_INTF_DATA] + for blade_intf in blade_intf_data.keys(): + if blade_intf_data[blade_intf]\ + [const.BLADE_INTF_RESERVATION] == \ + const.BLADE_INTF_RESERVED and \ + blade_intf_data[blade_intf]\ + [const.TENANTID] == tenant_id and \ + blade_intf_data[blade_intf]\ + [const.INSTANCE_ID] == instance_id: + return blade_intf_data[blade_intf]\ + [const.BLADE_INTF_RHEL_DEVICE_NAME] + return None + + def add_blade(self, ucsm_ip, chassis_id, blade_id): + """Add a blade to the inventory""" + pass + + +def main(): + #client = UCSInventory() + #client.build_state() + ucsinv = UCSInventory() + reserved_nics = [] + ucsinv.build_inventory_state() + while True: + reserved_blade_dict = ucsinv.get_least_reserved_blade() + if not reserved_blade_dict: + print "No more unreserved blades\n" + break + + least_reserved_blade_ucsm = reserved_blade_dict[const.LEAST_RSVD_BLADE_UCSM] + least_reserved_blade_chassis = \ + reserved_blade_dict[const.LEAST_RSVD_BLADE_CHASSIS] + least_reserved_blade_id = \ + reserved_blade_dict[const.LEAST_RSVD_BLADE_ID] + least_reserved_blade_data = \ + reserved_blade_dict[const.LEAST_RSVD_BLADE_DATA] + reserved_nic_dict = \ + ucsinv.reserve_blade_interface(least_reserved_blade_ucsm, + least_reserved_blade_chassis, + least_reserved_blade_id, + least_reserved_blade_data, + "demo") + if reserved_nic_dict: + reserved_intf_nic_info = {const.RESERVED_INTERFACE_UCSM: + least_reserved_blade_ucsm, + const.RESERVED_INTERFACE_CHASSIS: + least_reserved_blade_chassis, + const.RESERVED_INTERFACE_BLADE: + least_reserved_blade_id, + const.RESERVED_INTERFACE_DN: + reserved_nic_dict[const.BLADE_INTF_DN]} + reserved_nics.append(reserved_intf_nic_info) + #break + + for rnic in reserved_nics: + ucsinv.unreserve_blade_interface( + rnic[const.RESERVED_INTERFACE_UCSM], + rnic[const.RESERVED_INTERFACE_CHASSIS], + rnic[const.RESERVED_INTERFACE_BLADE], + rnic[const.RESERVED_INTERFACE_DN]) + + +if __name__ == '__main__': + main() diff --git a/quantum/plugins/cisco/ucs/cisco_ucs_network_driver.py b/quantum/plugins/cisco/ucs/cisco_ucs_network_driver.py index faba86fcbd..dfb7839f2e 100644 --- a/quantum/plugins/cisco/ucs/cisco_ucs_network_driver.py +++ b/quantum/plugins/cisco/ucs/cisco_ucs_network_driver.py @@ -32,7 +32,8 @@ from quantum.plugins.cisco.common import cisco_exceptions as cexc from quantum.plugins.cisco.ucs import cisco_getvif as gvif -LOG.basicConfig(level=LOG.WARN) +LOG.basicConfig(level=LOG.DEBUG) +#LOG.basicConfig(level=LOG.WARN) LOG.getLogger(const.LOGGER_COMPONENT_NAME) COOKIE_VALUE = "cookie_placeholder" @@ -41,6 +42,9 @@ PROFILE_CLIENT = "profileclient_placeholder" VLAN_NAME = "vlanname_placeholder" VLAN_ID = "vlanid_placeholder" OLD_VLAN_NAME = "old_vlanname_placeholder" +BLADE_VALUE = "blade_number_placeholder" +BLADE_DN_VALUE = "blade_dn_placeholder" +CHASSIS_VALUE = "chassis_number_placeholder" DYNAMIC_NIC_PREFIX = "eth" # The following are standard strings, messages used to communicate with UCSM, @@ -112,6 +116,27 @@ DELETE_PROFILE = " " \ " " +GET_BLADE_INTERFACE_STATE = " " + \ + " " + +GET_BLADE_INTERFACE = "" + \ + " " + \ + " " + +# TODO (Sumit): Assumes "adaptor-1", check if this has to be discovered too +GET_BLADE_INTERFACES = " " + \ + " " + class CiscoUCSMDriver(): """UCSM Driver""" @@ -130,6 +155,7 @@ class CiscoUCSMDriver(): LOG.debug(response.status) LOG.debug(response.reason) LOG.debug(response_data) + #print("***Sumit: response %s") % response_data # TODO (Sumit): If login is not successful, throw exception xml_tree = et.XML(response_data) cookie = xml_tree.attrib["outCookie"] @@ -142,6 +168,8 @@ class CiscoUCSMDriver(): LOG.debug(response.status) LOG.debug(response.reason) LOG.debug("UCSM Response: %s" % response_data) + #print("***Sumit: response %s") % response_data + post_data_response = response_data logout_data = "" conn.request(METHOD, URL, logout_data, HEADERS) @@ -150,6 +178,8 @@ class CiscoUCSMDriver(): LOG.debug(response.status) LOG.debug(response.reason) LOG.debug(response_data) + #print("***Sumit: response %s") % response_data + return post_data_response def _create_vlan_post_data(self, vlan_name, vlan_id): """Create command""" @@ -196,6 +226,81 @@ class CiscoUCSMDriver(): else: raise cexc.NoMoreNics() + def _get_blade_interfaces_post_data(self, chassis_number, blade_number): + data = GET_BLADE_INTERFACES.replace(CHASSIS_VALUE, chassis_number) + data = data.replace(BLADE_VALUE, blade_number) + return data + + def _get_blade_interface_state_post_data(self, blade_dn): + data = GET_BLADE_INTERFACE_STATE.replace(BLADE_DN_VALUE, blade_dn) + return data + + def _get_blade_interfaces(self, chassis_number, blade_number, ucsm_ip, + ucsm_username, ucsm_password): + data = self._get_blade_interfaces_post_data(chassis_number, + blade_number) + response = self._post_data(ucsm_ip, ucsm_username, ucsm_password, data) + """ + print("***Sumit: ucsmp_ip %s ucsm_username %s ucsm_password %s data %s \ + response %s") % (ucsm_ip, ucsm_username, ucsm_password, data, + response) + """ + elements = \ + et.XML(response).find("outConfigs").findall("adaptorHostEthIf") + bladeInterfaces = {} + for element in elements: + dn = element.get("dn", default=None) + if dn: + order = element.get("order", default=None) + bladeInterface = {const.BLADE_INTF_DN: dn, + const.BLADE_INTF_ORDER: order, + const.BLADE_INTF_LINK_STATE: None, + const.BLADE_INTF_OPER_STATE: None, + const.BLADE_INTF_INST_TYPE: None, + const.BLADE_INTF_RHEL_DEVICE_NAME: + self._get_rhel_device_name(order)} + bladeInterfaces[dn] = bladeInterface + + return bladeInterfaces + + def _get_blade_interface_state(self, bladeIntf, ucsm_ip, + ucsm_username, ucsm_password): + data = \ + self._get_blade_interface_state_post_data(bladeIntf[const.BLADE_INTF_DN]) + response = self._post_data(ucsm_ip, ucsm_username, ucsm_password, data) + elements = \ + et.XML(response).find("outConfigs").findall("dcxVIf") + for element in elements: + bladeIntf[const.BLADE_INTF_LINK_STATE] = element.get("linkState", + default=None) + bladeIntf[const.BLADE_INTF_OPER_STATE] = element.get("operState", + default=None) + bladeIntf[const.BLADE_INTF_INST_TYPE] = element.get("instType", + default=None) + + def _get_rhel_device_name(self, order): + deviceName = const.RHEL_DEVICE_NAME_REPFIX + str(int(order) - 1) + return deviceName + + def _get_dynamic_interface(self, chassis_number, blade_number, + ucsm_ip,ucsm_username, + ucsm_password): + bladeInterfaces = client._get_blade_interfaces(chassis_number, + blade_number, + ucsm_ip, + ucsm_username, + ucsm_password) + for bladeIntf in bladeInterfaces.values(): + client._get_blade_interface_state(bladeIntf, ucsm_ip, + ucsm_username, ucsm_password) + if bladeIntf[const.BLADE_INTF_INST_TYPE] == \ + const.BLADE_INTF_DYNAMIC and \ + bladeIntf[const.BLADE_INTF_LINK_STATE] == \ + const.BLADE_INTF_STATE_UNKNOWN and \ + bladeIntf[const.BLADE_INTF_OPER_STATE] == \ + const.BLADE_INTF_STATE_UNKNOWN: + return bladeIntf + def create_vlan(self, vlan_name, vlan_id, ucsm_ip, ucsm_username, ucsm_password): """Create request for UCSM""" @@ -234,6 +339,26 @@ class CiscoUCSMDriver(): LOG.debug("Reserving dynamic nic %s" % dynamic_nic_name) return dynamic_nic_name + def get_blade_data(self, chassis_number, blade_number, + ucsm_ip,ucsm_username, + ucsm_password): + """ + Returns only the dynamic interfaces on the blade + """ + bladeInterfaces = self._get_blade_interfaces(chassis_number, + blade_number, + ucsm_ip, + ucsm_username, + ucsm_password) + for bladeIntf in bladeInterfaces.keys(): + self._get_blade_interface_state(bladeInterfaces[bladeIntf], ucsm_ip, + ucsm_username, ucsm_password) + if bladeInterfaces[bladeIntf][const.BLADE_INTF_INST_TYPE] != \ + const.BLADE_INTF_DYNAMIC: + bladeInterfaces.pop(bladeIntf) + + return bladeInterfaces + def delete_vlan(self, vlan_name, ucsm_ip, ucsm_username, ucsm_password): """Create request for UCSM""" data = self._delete_vlan_post_data(vlan_name) diff --git a/quantum/plugins/cisco/ucs/cisco_ucs_plugin.py b/quantum/plugins/cisco/ucs/cisco_ucs_plugin.py index f6b7daf5ff..d2f85fef74 100644 --- a/quantum/plugins/cisco/ucs/cisco_ucs_plugin.py +++ b/quantum/plugins/cisco/ucs/cisco_ucs_plugin.py @@ -42,10 +42,6 @@ class UCSVICPlugin(L2DevicePluginBase): self._client = utils.import_object(conf.UCSM_DRIVER) LOG.debug("Loaded driver %s\n" % conf.UCSM_DRIVER) self._utils = cutil.DBUtils() - # TODO (Sumit) This is for now, when using only one chassis - self._ucsm_ip = conf.UCSM_IP_ADDRESS - self._ucsm_username = cred.Store.getUsername(conf.UCSM_IP_ADDRESS) - self._ucsm_password = cred.Store.getPassword(conf.UCSM_IP_ADDRESS) # TODO (Sumit) Make the counter per UCSM self._port_profile_counter = 0 @@ -56,6 +52,7 @@ class UCSVICPlugin(L2DevicePluginBase): the specified tenant. """ LOG.debug("UCSVICPlugin:get_all_networks() called\n") + self._set_ucsm(kwargs[const.DEVICE_IP]) return self._networks.values() def create_network(self, tenant_id, net_name, net_id, vlan_name, vlan_id, @@ -65,6 +62,7 @@ class UCSVICPlugin(L2DevicePluginBase): a symbolic name. """ LOG.debug("UCSVICPlugin:create_network() called\n") + self._set_ucsm(kwargs[const.DEVICE_IP]) self._client.create_vlan(vlan_name, str(vlan_id), self._ucsm_ip, self._ucsm_username, self._ucsm_password) new_net_dict = {const.NET_ID: net_id, @@ -81,6 +79,7 @@ class UCSVICPlugin(L2DevicePluginBase): belonging to the specified tenant. """ LOG.debug("UCSVICPlugin:delete_network() called\n") + self._set_ucsm(kwargs[const.DEVICE_IP]) net = self._networks.get(net_id) # TODO (Sumit) : Verify that no attachments are plugged into the # network @@ -99,6 +98,7 @@ class UCSVICPlugin(L2DevicePluginBase): spec """ LOG.debug("UCSVICPlugin:get_network_details() called\n") + self._set_ucsm(kwargs[const.DEVICE_IP]) network = self._get_network(tenant_id, net_id) return network @@ -108,6 +108,7 @@ class UCSVICPlugin(L2DevicePluginBase): Virtual Network. """ LOG.debug("UCSVICPlugin:rename_network() called\n") + self._set_ucsm(kwargs[const.DEVICE_IP]) network = self._get_network(tenant_id, net_id) network[const.NET_NAME] = new_name return network @@ -118,6 +119,7 @@ class UCSVICPlugin(L2DevicePluginBase): specified Virtual Network. """ LOG.debug("UCSVICPlugin:get_all_ports() called\n") + self._set_ucsm(kwargs[const.DEVICE_IP]) network = self._get_network(tenant_id, net_id) ports_on_net = network[const.NET_PORTS].values() return ports_on_net @@ -127,27 +129,28 @@ class UCSVICPlugin(L2DevicePluginBase): Creates a port on the specified Virtual Network. """ LOG.debug("UCSVICPlugin:create_port() called\n") + self._set_ucsm(kwargs[const.DEVICE_IP]) + 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] net = self._get_network(tenant_id, net_id) ports = net[const.NET_PORTS] - # TODO (Sumit): This works on a single host deployment, - # in multi-host environment, dummy needs to be replaced with the - # hostname - dynamic_nic_name = self._client.get_dynamic_nic("dummy") 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] - sql_query = "INSERT INTO ports (port_id, profile_name, dynamic_vnic," \ - "host, instance_name, instance_nic_name, used) VALUES" \ - "('%s', '%s', '%s', 'dummy', NULL, NULL, 0)" % \ - (port_id, profile_name, dynamic_nic_name) - self._utils.execute_db_query(sql_query) new_port_dict = {const.PORT_ID: port_id, const.PORT_STATE: const.PORT_UP, const.ATTACHMENT: None, const.PORT_PROFILE: new_port_profile} ports[port_id] = new_port_dict + ucs_inventory.reserve_blade_interface(self._ucsm_ip, chassis_id, + blade_id, blade_data_dict, + tenant_id, port_id, + portprofile_name) return new_port_dict def delete_port(self, tenant_id, net_id, port_id, **kwargs): @@ -158,6 +161,11 @@ class UCSVICPlugin(L2DevicePluginBase): then the port can be deleted. """ LOG.debug("UCSVICPlugin:delete_port() called\n") + self._set_ucsm(kwargs[const.DEVICE_IP]) + ucs_inventory = kwargs[const.UCS_INVENTORY] + chassis_id = kwargs[const.const.CHASSIS_ID] + blade_id = kwargs[const.const.BLADE_ID] + interface_dn = kwargs[const.BLADE_INTF_DN] port = self._get_port(tenant_id, net_id, port_id) if port[const.ATTACHMENT]: raise exc.PortInUse(net_id=net_id, port_id=port_id, @@ -169,11 +177,10 @@ class UCSVICPlugin(L2DevicePluginBase): port_profile = port[const.PORT_PROFILE] self._delete_port_profile(port_id, port_profile[const.PROFILE_NAME]) - sql_query = "delete from ports where port_id = \"%s\"" % \ - (port[const.PORT_ID]) - self._utils.execute_db_query(sql_query) net = self._get_network(tenant_id, net_id) net[const.NET_PORTS].pop(port_id) + ucs_inventory.unreserve_blade_interface(ucsm_ip, chassis_id, + blade_id, interface_dn) except KeyError: raise exc.PortNotFound(net_id=net_id, port_id=port_id) @@ -182,6 +189,7 @@ class UCSVICPlugin(L2DevicePluginBase): Updates the state of a port on the specified Virtual Network. """ LOG.debug("UCSVICPlugin:update_port() called\n") + self._set_ucsm(kwargs[const.DEVICE_IP]) port = self._get_port(tenant_id, net_id, port_id) self._validate_port_state(port_state) port[const.PORT_STATE] = port_state @@ -193,6 +201,7 @@ class UCSVICPlugin(L2DevicePluginBase): that is attached to this particular port. """ LOG.debug("UCSVICPlugin:get_port_details() called\n") + self._set_ucsm(kwargs[const.DEVICE_IP]) return self._get_port(tenant_id, net_id, port_id) def plug_interface(self, tenant_id, net_id, port_id, remote_interface_id, @@ -202,6 +211,7 @@ class UCSVICPlugin(L2DevicePluginBase): specified Virtual Network. """ LOG.debug("UCSVICPlugin:plug_interface() called\n") + self._set_ucsm(kwargs[const.DEVICE_IP]) self._validate_attachment(tenant_id, net_id, port_id, remote_interface_id) port = self._get_port(tenant_id, net_id, port_id) @@ -227,6 +237,7 @@ class UCSVICPlugin(L2DevicePluginBase): specified Virtual Network. """ LOG.debug("UCSVICPlugin:unplug_interface() called\n") + self._set_ucsm(kwargs[const.DEVICE_IP]) port = self._get_port(tenant_id, net_id, port_id) port[const.ATTACHMENT] = None port_profile = port[const.PORT_PROFILE] @@ -308,3 +319,9 @@ class UCSVICPlugin(L2DevicePluginBase): self._client.delete_profile(profile_name, self._ucsm_ip, self._ucsm_username, self._ucsm_password) self._port_profile_counter -= 1 + + def _set_ucsm(self, ucsm_ip): + 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) + From cd405409b4c765782f4e22f8085dc239fcf3ce47 Mon Sep 17 00:00:00 2001 From: Sumit Naiksatam Date: Fri, 19 Aug 2011 22:02:16 -0700 Subject: [PATCH 02/39] pylint and pep8 fixes. --- .../cisco/l2network_plugin_configuration.py | 3 + .../cisco/l2network_segmentation_base.py | 2 +- .../cisco/models/l2network_multi_blade.py | 8 +- .../cisco/models/l2network_single_blade.py | 2 +- .../cisco/segmentation/l2network_vlan_mgr.py | 4 +- .../plugins/cisco/ucs/cisco_ucs_inventory.py | 24 ++-- .../cisco/ucs/cisco_ucs_network_driver.py | 107 +++++------------- quantum/plugins/cisco/ucs/cisco_ucs_plugin.py | 10 +- 8 files changed, 62 insertions(+), 98 deletions(-) diff --git a/quantum/plugins/cisco/l2network_plugin_configuration.py b/quantum/plugins/cisco/l2network_plugin_configuration.py index acbca503b3..45eadd172e 100644 --- a/quantum/plugins/cisco/l2network_plugin_configuration.py +++ b/quantum/plugins/cisco/l2network_plugin_configuration.py @@ -46,6 +46,9 @@ MAX_NETWORKS = SECTION_CONF['max_networks'] SECTION_CONF = CONF_PARSER_OBJ['MODEL'] MODEL_CLASS = SECTION_CONF['model_class'] +SECTION_CONF = CONF_PARSER_OBJ['SEGMENTATION'] +MANAGER_CLASS = SECTION_CONF['manager_class'] + CONF_FILE = "conf/plugins.ini" CONF_PARSER_OBJ = confp.\ diff --git a/quantum/plugins/cisco/l2network_segmentation_base.py b/quantum/plugins/cisco/l2network_segmentation_base.py index d7b4378b8b..081d50fdfb 100644 --- a/quantum/plugins/cisco/l2network_segmentation_base.py +++ b/quantum/plugins/cisco/l2network_segmentation_base.py @@ -56,7 +56,7 @@ class L2NetworkSegmentationMgrBase(object): marked with the abstractmethod decorator is provided by the plugin class. """ - if cls is L2NetworkSegementationMgrBase: + if cls is L2NetworkSegmentationMgrBase: for method in cls.__abstractmethods__: method_ok = False for base in klass.__mro__: diff --git a/quantum/plugins/cisco/models/l2network_multi_blade.py b/quantum/plugins/cisco/models/l2network_multi_blade.py index c5ba157d29..fb68c5ec56 100644 --- a/quantum/plugins/cisco/models/l2network_multi_blade.py +++ b/quantum/plugins/cisco/models/l2network_multi_blade.py @@ -21,12 +21,13 @@ import inspect import logging as LOG +import platform from quantum.common import utils from quantum.plugins.cisco.l2network_model_base import L2NetworkModelBase from quantum.plugins.cisco import l2network_plugin_configuration as conf from quantum.plugins.cisco.common import cisco_constants as const -from quantum.plugins.cisco.ucs import cisco_ucs_inventory as ucsinv +from quantum.plugins.cisco.ucs import cisco_ucs_inventory as ucsinv LOG.basicConfig(level=LOG.WARN) LOG.getLogger(const.LOGGER_COMPONENT_NAME) @@ -130,8 +131,8 @@ class L2NetworkMultiBlade(L2NetworkModelBase): device_params = \ {const.DEVICE_IP: rsvd_info[const.UCSM_IP], const.UCS_INVENTORY: self._ucs_inventory, - const.CHASSIS_ID: rsvd_info[const.const.CHASSIS_ID], - const.BLADE_ID: rsvd_info[const.const.BLADE_ID], + const.CHASSIS_ID: rsvd_info[const.CHASSIS_ID], + const.BLADE_ID: rsvd_info[const.BLADE_ID], const.BLADE_INTF_DN: rsvd_info[const.BLADE_INTF_DN]} self._invoke_ucs_plugin(self._func_name(), args, device_params) @@ -167,4 +168,3 @@ class L2NetworkMultiBlade(L2NetworkModelBase): vif_desc = {const.VIF_DESC: {const.DEVICENAME: "eth2", const.UCSPROFILE: "default"}} return vif_desc - diff --git a/quantum/plugins/cisco/models/l2network_single_blade.py b/quantum/plugins/cisco/models/l2network_single_blade.py index 286f5c7dde..b4277af1a7 100644 --- a/quantum/plugins/cisco/models/l2network_single_blade.py +++ b/quantum/plugins/cisco/models/l2network_single_blade.py @@ -21,6 +21,7 @@ import inspect import logging as LOG +import platform from quantum.common import utils from quantum.plugins.cisco.l2network_model_base import L2NetworkModelBase @@ -136,4 +137,3 @@ class L2NetworkSinlgeBlade(L2NetworkModelBase): vif_desc = {const.VIF_DESC: {const.DEVICENAME: "eth2", const.UCSPROFILE: "default"}} return vif_desc - diff --git a/quantum/plugins/cisco/segmentation/l2network_vlan_mgr.py b/quantum/plugins/cisco/segmentation/l2network_vlan_mgr.py index 427ab690f6..533b488d54 100644 --- a/quantum/plugins/cisco/segmentation/l2network_vlan_mgr.py +++ b/quantum/plugins/cisco/segmentation/l2network_vlan_mgr.py @@ -21,7 +21,6 @@ import logging as LOG -from quantum.common import utils 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 \ @@ -30,6 +29,7 @@ from quantum.plugins.cisco.l2network_segmentation_base \ LOG.basicConfig(level=LOG.WARN) LOG.getLogger(const.LOGGER_COMPONENT_NAME) + class L2NetworkVLANMgr(L2NetworkSegmentationMgrBase): """ VLAN Manager which gets VLAN ID from DB @@ -39,9 +39,7 @@ class L2NetworkVLANMgr(L2NetworkSegmentationMgrBase): """Get an available VLAN ID""" return cdb.reserve_vlanid() - def release_segmentation_id(self, tenant_id, net_id, **kwargs): """Release the ID""" vlan_binding = cdb.get_vlan_binding(net_id) return cdb.release_vlanid(vlan_binding[const.VLANID]) - diff --git a/quantum/plugins/cisco/ucs/cisco_ucs_inventory.py b/quantum/plugins/cisco/ucs/cisco_ucs_inventory.py index a272c0ae00..ddc5eff3cf 100644 --- a/quantum/plugins/cisco/ucs/cisco_ucs_inventory.py +++ b/quantum/plugins/cisco/ucs/cisco_ucs_inventory.py @@ -1,3 +1,4 @@ +""" # vim: tabstop=4 shiftwidth=4 softtabstop=4 # # Copyright 2011 Cisco Systems, Inc. All rights reserved. @@ -16,7 +17,7 @@ # # @author: Sumit Naiksatam, Cisco Systems, Inc. # - +""" import logging as LOG from quantum.common import exceptions as exc @@ -38,7 +39,12 @@ The _inventory data strcuture contains a nested disctioary: } """ + class UCSInventory(object): + """ + Manages the state of all the UCS chasses, and blades in + the system + """ _inventory = {} _host_names = {} @@ -102,13 +108,13 @@ class UCSInventory(object): return blade_data def get_all_ucsms(self): + """Get the IPs of all the UCSMs in the system""" return self._inventory.keys() def reload_inventory(self): """Reload the inventory from a conf file""" self._load_inventory() - pass - + def build_inventory_state(self): """Populate the state of all the blades""" for ucsm_ip in self._inventory.keys(): @@ -195,7 +201,8 @@ class UCSInventory(object): const.BLADE_INTF_RESERVED blade_intf_data[blade_intf][const.TENANTID] = tenant_id blade_intf_data[blade_intf][const.PORTID] = port_id - blade_intf_data[blade_intf][const.PROFILEID] = portprofile_name + blade_intf_data[blade_intf][const.PROFILE_ID] = \ + portprofile_name blade_intf_data[blade_intf][const.INSTANCE_ID] = None dev_eth_name = blade_intf_data[blade_intf] \ [const.BLADE_INTF_RHEL_DEVICE_NAME] @@ -253,14 +260,14 @@ class UCSInventory(object): blade_intf_info = {const.UCSM_IP: ucsm_ip, const.CHASSIS_ID: chassis_id, const.BLADE_ID: blade_id, - const.BLADE_INTF_DN: + const.BLADE_INTF_DN: interface_dn} return blade_intf_info return None def get_host_name(self, tenant_id, instance_id): """ - Return the hostname of the blade with a reserved instance + Return the hostname of the blade with a reserved instance for this tenant """ for ucsm_ip in self._inventory_state.keys(): @@ -324,7 +331,8 @@ def main(): print "No more unreserved blades\n" break - least_reserved_blade_ucsm = reserved_blade_dict[const.LEAST_RSVD_BLADE_UCSM] + least_reserved_blade_ucsm = \ + reserved_blade_dict[const.LEAST_RSVD_BLADE_UCSM] least_reserved_blade_chassis = \ reserved_blade_dict[const.LEAST_RSVD_BLADE_CHASSIS] least_reserved_blade_id = \ @@ -336,7 +344,7 @@ def main(): least_reserved_blade_chassis, least_reserved_blade_id, least_reserved_blade_data, - "demo") + "demo", "12345", "profilename") if reserved_nic_dict: reserved_intf_nic_info = {const.RESERVED_INTERFACE_UCSM: least_reserved_blade_ucsm, diff --git a/quantum/plugins/cisco/ucs/cisco_ucs_network_driver.py b/quantum/plugins/cisco/ucs/cisco_ucs_network_driver.py index dfb7839f2e..2a1e380421 100644 --- a/quantum/plugins/cisco/ucs/cisco_ucs_network_driver.py +++ b/quantum/plugins/cisco/ucs/cisco_ucs_network_driver.py @@ -125,7 +125,7 @@ GET_BLADE_INTERFACE = "" + \ " " + \ " " @@ -218,88 +218,61 @@ class CiscoUCSMDriver(): data = DELETE_PROFILE.replace(PROFILE_NAME, profile_name) return data - def _get_next_dynamic_nic(self): - """Get an avaialble dynamic nic on the host""" - dynamic_nic_id = gvif.get_next_dynic() - if len(dynamic_nic_id) > 0: - return dynamic_nic_id - else: - raise cexc.NoMoreNics() - def _get_blade_interfaces_post_data(self, chassis_number, blade_number): + """Create command""" data = GET_BLADE_INTERFACES.replace(CHASSIS_VALUE, chassis_number) data = data.replace(BLADE_VALUE, blade_number) return data - - def _get_blade_interface_state_post_data(self, blade_dn): + + def _get_blade_intf_st_post_data(self, blade_dn): + """Create command""" data = GET_BLADE_INTERFACE_STATE.replace(BLADE_DN_VALUE, blade_dn) return data - + def _get_blade_interfaces(self, chassis_number, blade_number, ucsm_ip, ucsm_username, ucsm_password): + """Create command""" data = self._get_blade_interfaces_post_data(chassis_number, blade_number) response = self._post_data(ucsm_ip, ucsm_username, ucsm_password, data) - """ - print("***Sumit: ucsmp_ip %s ucsm_username %s ucsm_password %s data %s \ - response %s") % (ucsm_ip, ucsm_username, ucsm_password, data, - response) - """ elements = \ et.XML(response).find("outConfigs").findall("adaptorHostEthIf") - bladeInterfaces = {} + blade_interfaces = {} for element in elements: - dn = element.get("dn", default=None) - if dn: + dist_name = element.get("dn", default=None) + if dist_name: order = element.get("order", default=None) - bladeInterface = {const.BLADE_INTF_DN: dn, + blade_interface = {const.BLADE_INTF_DN: dist_name, const.BLADE_INTF_ORDER: order, const.BLADE_INTF_LINK_STATE: None, const.BLADE_INTF_OPER_STATE: None, const.BLADE_INTF_INST_TYPE: None, const.BLADE_INTF_RHEL_DEVICE_NAME: self._get_rhel_device_name(order)} - bladeInterfaces[dn] = bladeInterface + blade_interfaces[dist_name] = blade_interface - return bladeInterfaces + return blade_interfaces - def _get_blade_interface_state(self, bladeIntf, ucsm_ip, + def _get_blade_interface_state(self, blade_intf, ucsm_ip, ucsm_username, ucsm_password): + """Create command""" data = \ - self._get_blade_interface_state_post_data(bladeIntf[const.BLADE_INTF_DN]) + self._get_blade_intf_st_post_data(blade_intf[const.BLADE_INTF_DN]) response = self._post_data(ucsm_ip, ucsm_username, ucsm_password, data) elements = \ et.XML(response).find("outConfigs").findall("dcxVIf") for element in elements: - bladeIntf[const.BLADE_INTF_LINK_STATE] = element.get("linkState", + blade_intf[const.BLADE_INTF_LINK_STATE] = element.get("linkState", default=None) - bladeIntf[const.BLADE_INTF_OPER_STATE] = element.get("operState", + blade_intf[const.BLADE_INTF_OPER_STATE] = element.get("operState", default=None) - bladeIntf[const.BLADE_INTF_INST_TYPE] = element.get("instType", + blade_intf[const.BLADE_INTF_INST_TYPE] = element.get("instType", default=None) def _get_rhel_device_name(self, order): - deviceName = const.RHEL_DEVICE_NAME_REPFIX + str(int(order) - 1) - return deviceName - - def _get_dynamic_interface(self, chassis_number, blade_number, - ucsm_ip,ucsm_username, - ucsm_password): - bladeInterfaces = client._get_blade_interfaces(chassis_number, - blade_number, - ucsm_ip, - ucsm_username, - ucsm_password) - for bladeIntf in bladeInterfaces.values(): - client._get_blade_interface_state(bladeIntf, ucsm_ip, - ucsm_username, ucsm_password) - if bladeIntf[const.BLADE_INTF_INST_TYPE] == \ - const.BLADE_INTF_DYNAMIC and \ - bladeIntf[const.BLADE_INTF_LINK_STATE] == \ - const.BLADE_INTF_STATE_UNKNOWN and \ - bladeIntf[const.BLADE_INTF_OPER_STATE] == \ - const.BLADE_INTF_STATE_UNKNOWN: - return bladeIntf + """Get the device name as on the RHEL host""" + device_name = const.RHEL_DEVICE_NAME_REPFIX + str(int(order) - 1) + return device_name def create_vlan(self, vlan_name, vlan_id, ucsm_ip, ucsm_username, ucsm_password): @@ -325,39 +298,26 @@ class CiscoUCSMDriver(): new_vlan_name) self._post_data(ucsm_ip, ucsm_username, ucsm_password, data) - def get_dynamic_nic(self, host): - """Get an avaialble dynamic nic on the host""" - # TODO (Sumit): Check availability per host - # TODO (Sumit): If not available raise exception - # TODO (Sumit): This simple logic assumes that create-port and - # spawn-VM happens in lock-step - # But we should support multiple create-port calls, - # followed by spawn-VM calls - # That would require managing a pool of available - # dynamic vnics per host - dynamic_nic_name = self._get_next_dynamic_nic() - LOG.debug("Reserving dynamic nic %s" % dynamic_nic_name) - return dynamic_nic_name - def get_blade_data(self, chassis_number, blade_number, - ucsm_ip,ucsm_username, + ucsm_ip, ucsm_username, ucsm_password): """ Returns only the dynamic interfaces on the blade """ - bladeInterfaces = self._get_blade_interfaces(chassis_number, + blade_interfaces = self._get_blade_interfaces(chassis_number, blade_number, ucsm_ip, ucsm_username, ucsm_password) - for bladeIntf in bladeInterfaces.keys(): - self._get_blade_interface_state(bladeInterfaces[bladeIntf], ucsm_ip, - ucsm_username, ucsm_password) - if bladeInterfaces[bladeIntf][const.BLADE_INTF_INST_TYPE] != \ + for blade_intf in blade_interfaces.keys(): + self._get_blade_interface_state(blade_interfaces[blade_intf], + ucsm_ip, ucsm_username, + ucsm_password) + if blade_interfaces[blade_intf][const.BLADE_INTF_INST_TYPE] != \ const.BLADE_INTF_DYNAMIC: - bladeInterfaces.pop(bladeIntf) + blade_interfaces.pop(blade_intf) - return bladeInterfaces + return blade_interfaces def delete_vlan(self, vlan_name, ucsm_ip, ucsm_username, ucsm_password): """Create request for UCSM""" @@ -369,8 +329,3 @@ class CiscoUCSMDriver(): """Create request for UCSM""" data = self._delete_profile_post_data(profile_name) self._post_data(ucsm_ip, ucsm_username, ucsm_password, data) - - def release_dynamic_nic(self, host): - """Release a reserved dynamic nic on the host""" - # TODO (Sumit): Release on a specific host - pass diff --git a/quantum/plugins/cisco/ucs/cisco_ucs_plugin.py b/quantum/plugins/cisco/ucs/cisco_ucs_plugin.py index d2f85fef74..3268fbcb3d 100644 --- a/quantum/plugins/cisco/ucs/cisco_ucs_plugin.py +++ b/quantum/plugins/cisco/ucs/cisco_ucs_plugin.py @@ -150,7 +150,7 @@ class UCSVICPlugin(L2DevicePluginBase): ucs_inventory.reserve_blade_interface(self._ucsm_ip, chassis_id, blade_id, blade_data_dict, tenant_id, port_id, - portprofile_name) + profile_name) return new_port_dict def delete_port(self, tenant_id, net_id, port_id, **kwargs): @@ -163,8 +163,8 @@ class UCSVICPlugin(L2DevicePluginBase): LOG.debug("UCSVICPlugin:delete_port() called\n") self._set_ucsm(kwargs[const.DEVICE_IP]) ucs_inventory = kwargs[const.UCS_INVENTORY] - chassis_id = kwargs[const.const.CHASSIS_ID] - blade_id = kwargs[const.const.BLADE_ID] + chassis_id = kwargs[const.CHASSIS_ID] + blade_id = kwargs[const.BLADE_ID] interface_dn = kwargs[const.BLADE_INTF_DN] port = self._get_port(tenant_id, net_id, port_id) if port[const.ATTACHMENT]: @@ -179,7 +179,7 @@ class UCSVICPlugin(L2DevicePluginBase): port_profile[const.PROFILE_NAME]) net = self._get_network(tenant_id, net_id) net[const.NET_PORTS].pop(port_id) - ucs_inventory.unreserve_blade_interface(ucsm_ip, chassis_id, + ucs_inventory.unreserve_blade_interface(self._ucsm_ip, chassis_id, blade_id, interface_dn) except KeyError: raise exc.PortNotFound(net_id=net_id, port_id=port_id) @@ -321,7 +321,7 @@ class UCSVICPlugin(L2DevicePluginBase): self._port_profile_counter -= 1 def _set_ucsm(self, ucsm_ip): + """Set the UCSM IP, username, and password""" 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) - From 9092441db4a33d5ccde7f32658b3251212eb9ccf Mon Sep 17 00:00:00 2001 From: Sumit Naiksatam Date: Sat, 20 Aug 2011 02:51:59 -0700 Subject: [PATCH 03/39] Several fixes to initial version. --- .../plugins/cisco/common/cisco_constants.py | 1 + quantum/plugins/cisco/l2network_plugin.py | 6 +- .../cisco/models/l2network_multi_blade.py | 20 ++- .../cisco/segmentation/l2network_vlan_mgr.py | 2 + .../plugins/cisco/ucs/cisco_ucs_inventory.py | 119 ++++++++++++++++-- .../ucs/cisco_ucs_inventory_configuration.py | 31 +++++ quantum/plugins/cisco/ucs/cisco_ucs_plugin.py | 2 - 7 files changed, 161 insertions(+), 20 deletions(-) create mode 100644 quantum/plugins/cisco/ucs/cisco_ucs_inventory_configuration.py diff --git a/quantum/plugins/cisco/common/cisco_constants.py b/quantum/plugins/cisco/common/cisco_constants.py index 02eb2d4311..197d3f0080 100644 --- a/quantum/plugins/cisco/common/cisco_constants.py +++ b/quantum/plugins/cisco/common/cisco_constants.py @@ -134,6 +134,7 @@ BLADE_ID = 'blade_id' HOST_NAME = 'host_name' INSTANCE_ID = 'instance_id' +VIF_ID = 'vif_id' UCS_INVENTORY = 'ucs_inventory' LEAST_RSVD_BLADE_DICT = 'least_rsvd_blade_dict' diff --git a/quantum/plugins/cisco/l2network_plugin.py b/quantum/plugins/cisco/l2network_plugin.py index a4b30953e7..4a231ab848 100644 --- a/quantum/plugins/cisco/l2network_plugin.py +++ b/quantum/plugins/cisco/l2network_plugin.py @@ -45,14 +45,14 @@ class L2Network(QuantumPluginBase): _credentials = {} def __init__(self): - self._vlan_counter = int(conf.VLAN_START) - 1 + cdb.initialize() self._model = utils.import_object(conf.MODEL_CLASS) self._vlan_mgr = utils.import_object(conf.MANAGER_CLASS) - cdb.initialize() # TODO (Sumit): The following should move to the segmentation module - cdb.create_vlanids() + #cdb.create_vlanids() self._qoslevels_counter = 0 self._credentials_counter = 0 + LOG.debug("L2Network plugin initialization done successfully\n") """ Core API implementation diff --git a/quantum/plugins/cisco/models/l2network_multi_blade.py b/quantum/plugins/cisco/models/l2network_multi_blade.py index fb68c5ec56..a6c98cfac2 100644 --- a/quantum/plugins/cisco/models/l2network_multi_blade.py +++ b/quantum/plugins/cisco/models/l2network_multi_blade.py @@ -23,10 +23,12 @@ import inspect import logging as LOG import platform +from quantum.common import exceptions as exc from quantum.common import utils from quantum.plugins.cisco.l2network_model_base import L2NetworkModelBase 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 from quantum.plugins.cisco.ucs import cisco_ucs_inventory as ucsinv LOG.basicConfig(level=LOG.WARN) @@ -116,6 +118,8 @@ class L2NetworkMultiBlade(L2NetworkModelBase): """Support for the Quantum core API call""" least_reserved_blade_dict = \ self._ucs_inventory.get_least_reserved_blade() + if not least_reserved_blade_dict: + raise cexc.NoMoreNics() ucsm_ip = least_reserved_blade_dict[const.LEAST_RSVD_BLADE_UCSM] device_params = {const.DEVICE_IP: ucsm_ip, const.UCS_INVENTORY: self._ucs_inventory, @@ -128,6 +132,8 @@ class L2NetworkMultiBlade(L2NetworkModelBase): rsvd_info = \ self._ucs_inventory.get_rsvd_blade_intf_by_port(args[0], args[2]) + if not rsvd_info: + raise exc.PortNotFound(net_id=args[1], port_id=args[2]) device_params = \ {const.DEVICE_IP: rsvd_info[const.UCSM_IP], const.UCS_INVENTORY: self._ucs_inventory, @@ -146,12 +152,22 @@ class L2NetworkMultiBlade(L2NetworkModelBase): def plug_interface(self, args): """Support for the Quantum core API call""" - device_params = {const.DEVICE_IP: ""} + rsvd_info = \ + self._ucs_inventory.get_rsvd_blade_intf_by_port(args[0], + args[2]) + if not rsvd_info: + raise exc.PortNotFound(net_id=args[1], port_id=args[2]) + device_params = {const.DEVICE_IP: rsvd_info[const.UCSM_IP]} self._invoke_ucs_plugin(self._func_name(), args, device_params) def unplug_interface(self, args): """Support for the Quantum core API call""" - device_params = {const.DEVICE_IP: ""} + rsvd_info = \ + self._ucs_inventory.get_rsvd_blade_intf_by_port(args[0], + args[2]) + if not rsvd_info: + raise exc.PortNotFound(net_id=args[1], port_id=args[2]) + device_params = {const.DEVICE_IP: rsvd_info[const.UCSM_IP]} self._invoke_ucs_plugin(self._func_name(), args, device_params) def get_host(self, args): diff --git a/quantum/plugins/cisco/segmentation/l2network_vlan_mgr.py b/quantum/plugins/cisco/segmentation/l2network_vlan_mgr.py index 533b488d54..f361980a4d 100644 --- a/quantum/plugins/cisco/segmentation/l2network_vlan_mgr.py +++ b/quantum/plugins/cisco/segmentation/l2network_vlan_mgr.py @@ -34,6 +34,8 @@ class L2NetworkVLANMgr(L2NetworkSegmentationMgrBase): """ VLAN Manager which gets VLAN ID from DB """ + def __init__(self): + cdb.create_vlanids() def reserve_segmentation_id(self, tenant_id, net_name, **kwargs): """Get an available VLAN ID""" diff --git a/quantum/plugins/cisco/ucs/cisco_ucs_inventory.py b/quantum/plugins/cisco/ucs/cisco_ucs_inventory.py index ddc5eff3cf..ae9aa49708 100644 --- a/quantum/plugins/cisco/ucs/cisco_ucs_inventory.py +++ b/quantum/plugins/cisco/ucs/cisco_ucs_inventory.py @@ -18,6 +18,7 @@ # @author: Sumit Naiksatam, Cisco Systems, Inc. # """ +from copy import deepcopy import logging as LOG from quantum.common import exceptions as exc @@ -25,7 +26,8 @@ from quantum.plugins.cisco.common import cisco_constants as const from quantum.plugins.cisco.common import cisco_credentials as cred from quantum.plugins.cisco.common import cisco_exceptions as cexc from quantum.plugins.cisco.common import cisco_utils as cutil -from quantum.plugins.cisco.ucs import cisco_ucs_configuration as conf +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) @@ -38,6 +40,42 @@ The _inventory data strcuture contains a nested disctioary: "UCSM_IP: {"Chassis-ID": [Balde-ID]} } """ +""" +_inventory_state data structure is organized as below: +{ucsm_ip: + {chassis_id: + {blade_id: + {'blade-data': + {blade-dn-1: {blade-intf-data}, + blade-dn-2: {blade-intf-data} + } + } + } + } +} +'blade-data': Blade Data dictionary has the following keys: +=========================================================== +const.BLADE_INTF_DATA: This is a dictionary, with the key as the + dn of the interface, and the value as the + Blade Interface Dictionary described next +const.BLADE_UNRESERVED_INTF_COUNT: Number of unreserved interfaces + on this blade + +'blade-intf-data': Blade Interface dictionary has the following keys: +===================================================================== +const.BLADE_INTF_DN +const.BLADE_INTF_ORDER +const.BLADE_INTF_LINK_STATE +const.BLADE_INTF_OPER_STATE +const.BLADE_INTF_INST_TYPE +const.BLADE_INTF_RHEL_DEVICE_NAME +const.BLADE_INTF_RESERVATION +const.TENANTID +const.PORTID +const.PROFILE_ID +const.INSTANCE_ID +const.VIF_ID +""" class UCSInventory(object): @@ -56,7 +94,9 @@ class UCSInventory(object): def _load_inventory(self): """Load the inventory from a config file""" - inventory = conf.INVENTORY + inventory = deepcopy(conf.INVENTORY) + LOG.debug("Loaded UCS inventory: %s\n" % inventory) + for ucsm in inventory.keys(): ucsm_ip = inventory[ucsm][const.IP_ADDRESS] inventory[ucsm].pop(const.IP_ADDRESS) @@ -75,14 +115,47 @@ class UCSInventory(object): blade_list.append(blade_id) chassis_dict[chassis_id] = blade_list self._inventory[ucsm_ip] = chassis_dict + + self.build_inventory_state() def _get_host_name(self, ucsm_ip, chassis_id, blade_id): """Get the hostname based on the blade info""" host_key = ucsm_ip + "-" + chassis_id + "-" + blade_id return self._host_names[host_key] - def _get_blade_state(self, chassis_id, blade_id, ucsm_ip, ucsm_username, - ucsm_password): + def _get_initial_blade_state(self, chassis_id, blade_id, ucsm_ip, + ucsm_username, ucsm_password): + """Get the initial blade state""" + blade_intf_data = self._client.get_blade_data(chassis_id, blade_id, + ucsm_ip, ucsm_username, + ucsm_password) + unreserved_counter = 0 + + for blade_intf in blade_intf_data.keys(): + if (blade_intf_data[blade_intf][const.BLADE_INTF_LINK_STATE] == \ + const.BLADE_INTF_STATE_UNALLOCATED or \ + blade_intf_data[blade_intf][const.BLADE_INTF_LINK_STATE] == \ + const.BLADE_INTF_STATE_UNKNOWN) and \ + blade_intf_data[blade_intf][const.BLADE_INTF_OPER_STATE] == \ + const.BLADE_INTF_STATE_UNKNOWN: + blade_intf_data[blade_intf][const.BLADE_INTF_RESERVATION] = \ + const.BLADE_INTF_UNRESERVED + unreserved_counter += 1 + else: + blade_intf_data[blade_intf][const.BLADE_INTF_RESERVATION] = \ + const.BLADE_INTF_RESERVED + blade_intf_data[blade_intf][const.TENANTID] = None + blade_intf_data[blade_intf][const.PORTID] = None + blade_intf_data[blade_intf][const.PROFILE_ID] = None + blade_intf_data[blade_intf][const.INSTANCE_ID] = None + blade_intf_data[blade_intf][const.VIF_ID] = None + + blade_data = {const.BLADE_INTF_DATA: blade_intf_data, + const.BLADE_UNRESERVED_INTF_COUNT: unreserved_counter} + return blade_data + + def _get_blade_state(self, chassis_id, blade_id, ucsm_ip, + ucsm_username, ucsm_password): """Get the blade state""" blade_intf_data = self._client.get_blade_data(chassis_id, blade_id, ucsm_ip, ucsm_username, @@ -128,11 +201,14 @@ class UCSInventory(object): blades_dict = {} chasses_state[chassis_id] = blades_dict for blade_id in ucsm[chassis_id]: - blade_data = self._get_blade_state(chassis_id, blade_id, - ucsm_ip, ucsm_username, - ucsm_password) + blade_data = self._get_initial_blade_state(chassis_id, + blade_id, + ucsm_ip, + ucsm_username, + ucsm_password) blades_dict[blade_id] = blade_data + LOG.debug("UCS Inventory state is: %s\n" % self._inventory_state) return True def get_least_reserved_blade(self): @@ -182,12 +258,22 @@ class UCSInventory(object): old_blade_intf_data = blade_data_dict[const.BLADE_INTF_DATA] """ - We will now copy the older blade interface reservation state + We will now copy the older blade interface state """ for blade_intf in blade_intf_data.keys(): blade_intf_data[blade_intf][const.BLADE_INTF_RESERVATION] = \ old_blade_intf_data[blade_intf]\ [const.BLADE_INTF_RESERVATION] + blade_intf_data[blade_intf][const.TENANTID] = \ + old_blade_intf_data[blade_intf][const.TENANTID] + blade_intf_data[blade_intf][const.PORTID] = \ + old_blade_intf_data[blade_intf][const.PORTID] + blade_intf_data[blade_intf][const.PROFILE_ID] = \ + old_blade_intf_data[blade_intf][const.PROFILE_ID] + blade_intf_data[blade_intf][const.INSTANCE_ID] = \ + old_blade_intf_data[blade_intf][const.INSTANCE_ID] + blade_intf_data[blade_intf][const.VIF_ID] = \ + old_blade_intf_data[blade_intf][const.VIF_ID] blade_data[const.BLADE_UNRESERVED_INTF_COUNT] = \ blade_data_dict[const.BLADE_UNRESERVED_INTF_COUNT] @@ -228,12 +314,16 @@ class UCSInventory(object): """Unreserve a previously reserved interface on a blade""" ucsm_username = cred.Store.getUsername(ucsm_ip) ucsm_password = cred.Store.getPassword(ucsm_ip) - self._inventory_state[ucsm_ip][chassis_id][blade_id]\ - [const.BLADE_INTF_DATA] \ - [interface_dn][const.BLADE_INTF_RESERVATION] = \ - const.BLADE_INTF_UNRESERVED self._inventory_state[ucsm_ip][chassis_id][blade_id] \ [const.BLADE_UNRESERVED_INTF_COUNT] += 1 + blade_intf = self._inventory_state[ucsm_ip][chassis_id]\ + [blade_id][const.BLADE_INTF_DATA][interface_dn] + blade_intf[const.BLADE_INTF_RESERVATION] = const.BLADE_INTF_UNRESERVED + blade_intf[const.TENANTID] = None + blade_intf[const.PORTID] = None + blade_intf[const.PROFILE_ID] = None + blade_intf[const.INSTANCE_ID] = None + blade_intf[const.VIF_ID] = None LOG.debug("Unreserved blade interface %s\n" % interface_dn) def get_rsvd_blade_intf_by_port(self, tenant_id, port_id): @@ -292,7 +382,7 @@ class UCSInventory(object): return host_name return None - def get_instance_port(self, tenant_id, instance_id): + def get_instance_port(self, tenant_id, instance_id, vif_id): """ Return the device name for a reserved interface """ @@ -310,6 +400,9 @@ class UCSInventory(object): [const.TENANTID] == tenant_id and \ blade_intf_data[blade_intf]\ [const.INSTANCE_ID] == instance_id: + blade_intf_data[blade_intf][const.VIF_ID] = \ + vif_id + return blade_intf_data[blade_intf]\ [const.BLADE_INTF_RHEL_DEVICE_NAME] return None diff --git a/quantum/plugins/cisco/ucs/cisco_ucs_inventory_configuration.py b/quantum/plugins/cisco/ucs/cisco_ucs_inventory_configuration.py new file mode 100644 index 0000000000..3183658c36 --- /dev/null +++ b/quantum/plugins/cisco/ucs/cisco_ucs_inventory_configuration.py @@ -0,0 +1,31 @@ +""" +# 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: Sumit Naiksatam, Cisco Systems, Inc. +# +""" + +import os + +from quantum.plugins.cisco.common import cisco_configparser as confp + +CONF_FILE = "../conf/ucs_inventory.ini" + +CP = confp.CiscoConfigParser(os.path.dirname(os.path.realpath(__file__)) \ + + "/" + CONF_FILE) + +INVENTORY = CP.walk(CP.dummy) diff --git a/quantum/plugins/cisco/ucs/cisco_ucs_plugin.py b/quantum/plugins/cisco/ucs/cisco_ucs_plugin.py index 3268fbcb3d..87efa684cf 100644 --- a/quantum/plugins/cisco/ucs/cisco_ucs_plugin.py +++ b/quantum/plugins/cisco/ucs/cisco_ucs_plugin.py @@ -41,7 +41,6 @@ class UCSVICPlugin(L2DevicePluginBase): def __init__(self): self._client = utils.import_object(conf.UCSM_DRIVER) LOG.debug("Loaded driver %s\n" % conf.UCSM_DRIVER) - self._utils = cutil.DBUtils() # TODO (Sumit) Make the counter per UCSM self._port_profile_counter = 0 @@ -173,7 +172,6 @@ class UCSVICPlugin(L2DevicePluginBase): try: #TODO (Sumit): Before deleting port profile make sure that there # is no VM using this port profile - self._client.release_dynamic_nic("dummy") port_profile = port[const.PORT_PROFILE] self._delete_port_profile(port_id, port_profile[const.PROFILE_NAME]) From ba2cfc5080ca976ac1134ed03382c5080434934a Mon Sep 17 00:00:00 2001 From: Sumit Naiksatam Date: Sat, 20 Aug 2011 03:19:52 -0700 Subject: [PATCH 04/39] Reduced excessive logging. --- .../cisco/ucs/cisco_ucs_network_driver.py | 26 ++++++++----------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/quantum/plugins/cisco/ucs/cisco_ucs_network_driver.py b/quantum/plugins/cisco/ucs/cisco_ucs_network_driver.py index 2a1e380421..f75fc189d2 100644 --- a/quantum/plugins/cisco/ucs/cisco_ucs_network_driver.py +++ b/quantum/plugins/cisco/ucs/cisco_ucs_network_driver.py @@ -32,8 +32,7 @@ from quantum.plugins.cisco.common import cisco_exceptions as cexc from quantum.plugins.cisco.ucs import cisco_getvif as gvif -LOG.basicConfig(level=LOG.DEBUG) -#LOG.basicConfig(level=LOG.WARN) +LOG.basicConfig(level=LOG.WARN) LOG.getLogger(const.LOGGER_COMPONENT_NAME) COOKIE_VALUE = "cookie_placeholder" @@ -152,33 +151,30 @@ class CiscoUCSMDriver(): conn.request(METHOD, URL, login_data, HEADERS) response = conn.getresponse() response_data = response.read() - LOG.debug(response.status) - LOG.debug(response.reason) - LOG.debug(response_data) - #print("***Sumit: response %s") % response_data + #LOG.debug(response.status) + #LOG.debug(response.reason) + #LOG.debug(response_data) # TODO (Sumit): If login is not successful, throw exception xml_tree = et.XML(response_data) cookie = xml_tree.attrib["outCookie"] data = data.replace(COOKIE_VALUE, cookie) - LOG.debug("POST: %s" % data) + #LOG.debug("POST: %s" % data) conn.request(METHOD, URL, data, HEADERS) response = conn.getresponse() response_data = response.read() - LOG.debug(response.status) - LOG.debug(response.reason) - LOG.debug("UCSM Response: %s" % response_data) - #print("***Sumit: response %s") % response_data + #LOG.debug(response.status) + #LOG.debug(response.reason) + #LOG.debug("UCSM Response: %s" % response_data) post_data_response = response_data logout_data = "" conn.request(METHOD, URL, logout_data, HEADERS) response = conn.getresponse() response_data = response.read() - LOG.debug(response.status) - LOG.debug(response.reason) - LOG.debug(response_data) - #print("***Sumit: response %s") % response_data + #LOG.debug(response.status) + #LOG.debug(response.reason) + #LOG.debug(response_data) return post_data_response def _create_vlan_post_data(self, vlan_name, vlan_id): From cb1844ed8e91681ae019d7be64c43be404083a53 Mon Sep 17 00:00:00 2001 From: Sumit Naiksatam Date: Sat, 20 Aug 2011 08:57:38 -0700 Subject: [PATCH 05/39] Adding some error checks. --- quantum/plugins/cisco/l2network_plugin.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/quantum/plugins/cisco/l2network_plugin.py b/quantum/plugins/cisco/l2network_plugin.py index 4a231ab848..892dd14cd2 100644 --- a/quantum/plugins/cisco/l2network_plugin.py +++ b/quantum/plugins/cisco/l2network_plugin.py @@ -126,8 +126,8 @@ class L2Network(QuantumPluginBase): Gets the details of a particular network """ LOG.debug("get_network_details() called\n") - self._invoke_device_plugins(self._func_name(), [tenant_id, net_id]) network = db.network_get(net_id) + self._invoke_device_plugins(self._func_name(), [tenant_id, net_id]) ports_list = network[const.NETWORKPORTS] ports_on_net = [] for port in ports_list: @@ -149,6 +149,7 @@ class L2Network(QuantumPluginBase): Virtual Network. """ LOG.debug("rename_network() called\n") + network = db.network_get(net_id) self._invoke_device_plugins(self._func_name(), [tenant_id, net_id, new_name]) network = db.network_rename(tenant_id, net_id, new_name) @@ -163,8 +164,8 @@ class L2Network(QuantumPluginBase): specified Virtual Network. """ LOG.debug("get_all_ports() called\n") - self._invoke_device_plugins(self._func_name(), [tenant_id, net_id]) network = db.network_get(net_id) + self._invoke_device_plugins(self._func_name(), [tenant_id, net_id]) ports_list = network[const.NETWORKPORTS] ports_on_net = [] for port in ports_list: @@ -200,6 +201,7 @@ class L2Network(QuantumPluginBase): then the port can be deleted. """ LOG.debug("delete_port() called\n") + network = db.network_get(net_id) self._invoke_device_plugins(self._func_name(), [tenant_id, net_id, port_id]) db.port_destroy(net_id, port_id) @@ -211,6 +213,7 @@ class L2Network(QuantumPluginBase): Updates the state of a port on the specified Virtual Network. """ LOG.debug("update_port() called\n") + network = db.network_get(net_id) self._invoke_device_plugins(self._func_name(), [tenant_id, net_id, port_id, port_state]) self._validate_port_state(port_state) @@ -225,6 +228,7 @@ class L2Network(QuantumPluginBase): that is attached to this particular port. """ LOG.debug("get_port_details() called\n") + network = db.network_get(net_id) self._invoke_device_plugins(self._func_name(), [tenant_id, net_id, port_id]) port = db.port_get(net_id, port_id) @@ -241,6 +245,7 @@ class L2Network(QuantumPluginBase): specified Virtual Network. """ LOG.debug("plug_interface() called\n") + network = db.network_get(net_id) self._invoke_device_plugins(self._func_name(), [tenant_id, net_id, port_id, remote_interface_id]) @@ -252,6 +257,7 @@ class L2Network(QuantumPluginBase): specified Virtual Network. """ LOG.debug("unplug_interface() called\n") + network = db.network_get(net_id) self._invoke_device_plugins(self._func_name(), [tenant_id, net_id, port_id]) db.port_unset_attachment(net_id, port_id) From 58c64f3f1af78c991174f087a4722068bee38a31 Mon Sep 17 00:00:00 2001 From: rohitagarwalla Date: Sat, 20 Aug 2011 10:05:40 -0700 Subject: [PATCH 06/39] added ucs plugin related execptions in cisco_exceptions.py added ucs plugin persistence related modules - ucs_models.py and ucs_db.py added ucs db related unit tests in test_database.py fixed formatting in l2network_models.py and test_database.py --- .../plugins/cisco/common/cisco_exceptions.py | 40 ++ quantum/plugins/cisco/db/l2network_models.py | 6 +- quantum/plugins/cisco/db/ucs_db.py | 350 ++++++++++ quantum/plugins/cisco/db/ucs_models.py | 129 ++++ .../plugins/cisco/tests/unit/test_database.py | 644 +++++++++++++++++- 5 files changed, 1158 insertions(+), 11 deletions(-) create mode 100644 quantum/plugins/cisco/db/ucs_db.py create mode 100644 quantum/plugins/cisco/db/ucs_models.py diff --git a/quantum/plugins/cisco/common/cisco_exceptions.py b/quantum/plugins/cisco/common/cisco_exceptions.py index a50e2c86b2..d257f5ee18 100644 --- a/quantum/plugins/cisco/common/cisco_exceptions.py +++ b/quantum/plugins/cisco/common/cisco_exceptions.py @@ -110,6 +110,46 @@ class NexusPortBindingNotFound(exceptions.QuantumException): message = _("Nexus Port Binding %(port_id) is not present") +class UcsmBindingNotFound(exceptions.QuantumException): + """Ucsm Binding is not present""" + message = _("Ucsm Binding with ip %(ucsm_ip) is not present") + + +class UcsmBindingAlreadyExists(exceptions.QuantumException): + """Ucsm Binding already exists""" + message = _("Ucsm Binding with ip %(ucsm_ip) already exists") + + +class DynamicVnicNotFound(exceptions.QuantumException): + """Ucsm Binding is not present""" + message = _("Dyanmic Vnic %(vnic_id) is not present") + + +class DynamicVnicAlreadyExists(exceptions.QuantumException): + """Ucsm Binding already exists""" + message = _("Dynamic Vnic with name %(device_name) already exists") + + +class BladeNotFound(exceptions.QuantumException): + """Blade is not present""" + message = _("Blade %(blade_id) is not present") + + +class BladeAlreadyExists(exceptions.QuantumException): + """Blade already exists""" + message = _("Blade with mgmt_ip %(mgmt_ip) already exists") + + +class PortVnicBindingAlreadyExists(exceptions.QuantumException): + """PortVnic Binding already exists""" + message = _("PortVnic Binding %(port_id) already exists") + + +class PortVnicNotFound(exceptions.QuantumException): + """PortVnic Binding is not present""" + message = _("PortVnic Binding %(port_id) is not present") + + try: _("test") except NameError: diff --git a/quantum/plugins/cisco/db/l2network_models.py b/quantum/plugins/cisco/db/l2network_models.py index 8bc29d3984..52039ff61f 100644 --- a/quantum/plugins/cisco/db/l2network_models.py +++ b/quantum/plugins/cisco/db/l2network_models.py @@ -87,7 +87,7 @@ class VlanBinding(BASE, L2NetworkBase): vlan_id = Column(Integer, primary_key=True) vlan_name = Column(String(255)) - network_id = Column(String(255), ForeignKey("networks.uuid"), \ + network_id = Column(String(255), ForeignKey("networks.uuid"), nullable=False) network = relation(models.Network, uselist=False) @@ -128,9 +128,9 @@ class PortProfileBinding(BASE, L2NetworkBase): id = Column(Integer, primary_key=True, autoincrement=True) tenant_id = Column(String(255)) - port_id = Column(String(255), ForeignKey("ports.uuid"), \ + port_id = Column(String(255), ForeignKey("ports.uuid"), nullable=False) - portprofile_id = Column(String(255), ForeignKey("portprofiles.uuid"), \ + portprofile_id = Column(String(255), ForeignKey("portprofiles.uuid"), nullable=False) default = Column(Boolean) ports = relation(models.Port) diff --git a/quantum/plugins/cisco/db/ucs_db.py b/quantum/plugins/cisco/db/ucs_db.py new file mode 100644 index 0000000000..4cb96b2d24 --- /dev/null +++ b/quantum/plugins/cisco/db/ucs_db.py @@ -0,0 +1,350 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2011, Cisco Systems, Inc. +# +# 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: Rohit Agarwalla, Cisco Systems, Inc. + +import logging as LOG + +from sqlalchemy.orm import exc + +import quantum.plugins.cisco.db.api as db +import ucs_models + +from quantum.plugins.cisco.common import cisco_exceptions as c_exc + + +def get_all_ucsmbinding(): + """Lists all the ucsm bindings""" + LOG.debug("get_all_ucsmbinding() called") + session = db.get_session() + try: + bindings = session.query(ucs_models.UcsmBinding).\ + all() + return bindings + except exc.NoResultFound: + return [] + + +def get_ucsmbinding(ucsm_ip): + """Lists a ucsm binding""" + LOG.debug("get_ucsmbinding() called") + session = db.get_session() + try: + binding = session.query(ucs_models.UcsmBinding).\ + filter_by(ucsm_ip=ucsm_ip).\ + one() + return binding + except exc.NoResultFound: + raise c_exc.UcsmBindingNotFound(ucsm_ip=ucsm_ip) + + +def add_ucsmbinding(ucsm_ip, network_id): + """Adds a ucsm binding""" + LOG.debug("add_ucsmbinding() called") + session = db.get_session() + try: + binding = session.query(ucs_models.UcsmBinding).\ + filter_by(ucsm_ip=ucsm_ip).\ + one() + raise c_exc.UcsmBindingAlreadyExists(ucsm_ip=ucsm_ip) + except exc.NoResultFound: + binding = ucs_models.UcsmBinding(ucsm_ip, network_id) + session.add(binding) + session.flush() + return binding + + +def remove_ucsmbinding(ucsm_ip): + """Removes a ucsm binding""" + LOG.debug("remove_ucsmbinding() called") + session = db.get_session() + try: + binding = session.query(ucs_models.UcsmBinding).\ + filter_by(ucsm_ip=ucsm_ip).\ + one() + session.delete(binding) + session.flush() + return binding + except exc.NoResultFound: + pass + + +def update_ucsmbinding(ucsm_ip, new_network_id): + """Updates ucsm binding""" + LOG.debug("update_ucsmbinding() called") + session = db.get_session() + try: + binding = session.query(ucs_models.UcsmBinding).\ + filter_by(ucsm_ip=ucsm_ip).\ + one() + if new_network_id: + binding.network_id = new_network_id + session.merge(binding) + session.flush() + return binding + except exc.NoResultFound: + raise c_exc.UcsmBindingNotFound(ucsm_ip=ucsm_ip) + + +def get_all_dynamicvnics(): + """Lists all the dynamic vnics""" + LOG.debug("get_all_dynamicvnics() called") + session = db.get_session() + try: + vnics = session.query(ucs_models.DynamicVnic).\ + all() + return vnics + except exc.NoResultFound: + return [] + + +def get_dynamicvnic(vnic_id): + """Lists a dynamic vnic""" + LOG.debug("get_dynamicvnic() called") + session = db.get_session() + try: + vnic = session.query(ucs_models.DynamicVnic).\ + filter_by(uuid=vnic_id).\ + one() + return vnic + except exc.NoResultFound: + raise c_exc.DynamicVnicNotFound(vnic_id=vnic_id) + + +def add_dynamicvnic(device_name, blade_id, vnic_state): + """Adds a dynamic vnic""" + LOG.debug("add_dynamicvnic() called") + session = db.get_session() + try: + vnic = session.query(ucs_models.DynamicVnic).\ + filter_by(device_name=device_name).\ + one() + raise c_exc.DynamicVnicAlreadyExists(device_name=device_name) + except exc.NoResultFound: + vnic = ucs_models.DynamicVnic(device_name, blade_id, vnic_state) + session.add(vnic) + session.flush() + return vnic + + +def remove_dynamicvnic(vnic_id): + """Removes a dynamic vnic""" + LOG.debug("remove_dynamicvnic() called") + session = db.get_session() + try: + vnic = session.query(ucs_models.DynamicVnic).\ + filter_by(uuid=vnic_id).\ + one() + session.delete(vnic) + session.flush() + return vnic + except exc.NoResultFound: + pass + + +def update_dynamicvnic(vnic_id, new_device_name=None, new_blade_id=None, + vnic_state=None): + """Updates dynamic vnic""" + LOG.debug("update_dynamicvnic() called") + session = db.get_session() + try: + vnic = session.query(ucs_models.DynamicVnic).\ + filter_by(uuid=vnic_id).\ + one() + if new_device_name: + vnic.device_name = new_device_name + if new_blade_id: + vnic.blade_id = new_blade_id + if vnic_state: + vnic.vnic_state = vnic_state + session.merge(vnic) + session.flush() + return vnic + except exc.NoResultFound: + raise c_exc.DynamicVnicNotFound(vnic_id=vnic_id) + + +def get_all_blades(): + """Lists all the blades details""" + LOG.debug("get_all_blades() called") + session = db.get_session() + try: + blades = session.query(ucs_models.UcsBlade).\ + all() + return blades + except exc.NoResultFound: + return [] + + +def get_blade(blade_id): + """Lists a blade details""" + LOG.debug("get_blade() called") + session = db.get_session() + try: + blade = session.query(ucs_models.UcsBlade).\ + filter_by(uuid=blade_id).\ + one() + return blade + except exc.NoResultFound: + raise c_exc.BladeNotFound(blade_id=blade_id) + + +def add_blade(mgmt_ip, mac_addr, chassis_id, ucsm_ip, blade_state, + vnics_used, hostname): + """Adds a blade""" + LOG.debug("add_blade() called") + session = db.get_session() + try: + blade = session.query(ucs_models.UcsBlade).\ + filter_by(mgmt_ip=mgmt_ip).\ + one() + raise c_exc.BladeAlreadyExists(mgmt_ip=mgmt_ip) + except exc.NoResultFound: + blade = ucs_models.UcsBlade(mgmt_ip, mac_addr, chassis_id, ucsm_ip, + blade_state, vnics_used, hostname) + session.add(blade) + session.flush() + return blade + + +def remove_blade(blade_id): + """Removes a blade""" + LOG.debug("remove_blade() called") + session = db.get_session() + try: + blade = session.query(ucs_models.UcsBlade).\ + filter_by(uuid=blade_id).\ + one() + session.delete(blade) + session.flush() + return blade + except exc.NoResultFound: + pass + + +def update_blade(blade_id, new_mgmt_ip=None, new_mac_addr=None, + new_chassis_id=None, new_ucsm_ip=None, + new_blade_state=None, new_vnics_used=None, + new_hostname=None): + """Updates details of a blade""" + LOG.debug("update_blade() called") + session = db.get_session() + try: + blade = session.query(ucs_models.UcsBlade).\ + filter_by(uuid=blade_id).\ + one() + if new_mgmt_ip: + blade.mgmt_ip = new_mgmt_ip + if new_mac_addr: + blade.mac_addr = new_mac_addr + if new_chassis_id: + blade.chassis_id = new_chassis_id + if new_ucsm_ip: + blade.ucsm_ip = new_ucsm_ip + if new_blade_state: + blade.blade_state = new_blade_state + if new_vnics_used: + blade.vnics_used = new_vnics_used + if new_hostname: + blade.hostname = new_hostname + session.merge(blade) + session.flush() + return blade + except exc.NoResultFound: + raise c_exc.BladeNotFound(blade_id=blade_id) + + +def get_all_portbindings(): + """Lists all the port bindings""" + LOG.debug("db get_all_portbindings() called") + session = db.get_session() + try: + port_bindings = session.query(ucs_models.PortBinding).\ + all() + return port_bindings + except exc.NoResultFound: + return [] + + +def get_portbinding(port_id): + """Lists a port binding""" + LOG.debug("get_portbinding() called") + session = db.get_session() + try: + port_binding = session.query(ucs_models.PortBinding).\ + filter_by(port_id=port_id).\ + one() + return port_binding + except exc.NoResultFound: + raise c_exc.PortVnicNotFound(port_id=port_id) + + +def add_portbinding(port_id, dynamic_vnic_id, portprofile_name, + vlan_name, vlan_id, qos): + """Adds a port binding""" + LOG.debug("add_portbinding() called") + session = db.get_session() + try: + port_binding = session.query(ucs_models.PortBinding).\ + filter_by(port_id=port_id).\ + one() + raise c_exc.PortVnicBindingAlreadyExists(port_id=port_id) + except exc.NoResultFound: + port_binding = ucs_models.PortBinding(port_id, dynamic_vnic_id, \ + portprofile_name, vlan_name, vlan_id, qos) + session.add(port_binding) + session.flush() + return port_binding + + +def remove_portbinding(port_id): + """Removes a port binding""" + LOG.debug("db remove_portbinding() called") + session = db.get_session() + try: + port_binding = session.query(ucs_models.PortBinding).\ + filter_by(port_id=port_id).\ + one() + session.delete(port_binding) + session.flush() + return port_binding + except exc.NoResultFound: + pass + + +def update_portbinding(port_id, dynamic_vnic_id=None, portprofile_name=None, + vlan_name=None, vlan_id=None, qos=None): + """Updates port binding""" + LOG.debug("db update_portbinding() called") + session = db.get_session() + try: + port_binding = session.query(ucs_models.PortBinding).\ + filter_by(port_id=port_id).\ + one() + if dynamic_vnic_id: + port_binding.dynamic_vnic_id = dynamic_vnic_id + if portprofile_name: + port_binding.portprofile_name = portprofile_name + if vlan_name: + port_binding.vlan_name = vlan_name + if vlan_name: + port_binding.vlan_id = vlan_id + if qos: + port_binding.qos = qos + session.merge(port_binding) + session.flush() + return port_binding + except exc.NoResultFound: + raise c_exc.PortVnicNotFound(port_id=port_id) diff --git a/quantum/plugins/cisco/db/ucs_models.py b/quantum/plugins/cisco/db/ucs_models.py new file mode 100644 index 0000000000..a146ac828a --- /dev/null +++ b/quantum/plugins/cisco/db/ucs_models.py @@ -0,0 +1,129 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2011, Cisco Systems, Inc. +# +# 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: Rohit Agarwalla, Cisco Systems, Inc. + +import uuid + +from sqlalchemy import Column, Integer, String, ForeignKey +from sqlalchemy.orm import relation + +from quantum.plugins.cisco.db.l2network_models import L2NetworkBase +from quantum.plugins.cisco.db import models +from quantum.plugins.cisco.db.models import BASE + + +class UcsmBinding(BASE, L2NetworkBase): + """Represents a binding of ucsm to network_id""" + __tablename__ = 'ucsm_bindings' + + id = Column(Integer, primary_key=True, autoincrement=True) + ucsm_ip = Column(String(255)) + network_id = Column(String(255), ForeignKey("networks.uuid"), + nullable=False) + network = relation(models.Network) + + def __init__(self, ucsm_ip, network_id): + self.ucsm_ip = ucsm_ip + self.network_id = network_id + + def __repr__(self): + return "" % \ + (self.ucsm_ip, self.network_id) + + +class DynamicVnic(BASE, L2NetworkBase): + """Represents Cisco UCS Dynamic Vnics""" + __tablename__ = 'dynamic_vnics' + + uuid = Column(String(255), primary_key=True) + device_name = Column(String(255)) + blade_id = Column(String(255), ForeignKey("ucs_blades.uuid"), + nullable=False) + vnic_state = Column(String(255)) + + def __init__(self, device_name, blade_id, vnic_state): + self.uuid = uuid.uuid4() + self.device_name = device_name + self.blade_id = blade_id + self.vnic_state = vnic_state + + def __repr__(self): + return "" % \ + (self.uuid, self.device_name, self.blade_id, + self.vnic_state) + + +class UcsBlade(BASE, L2NetworkBase): + """Represents details of ucs blades""" + __tablename__ = 'ucs_blades' + + uuid = Column(String(255), primary_key=True) + mgmt_ip = Column(String(255)) + mac_addr = Column(String(255)) + chassis_id = Column(String(255)) + ucsm_ip = Column(String(255)) + blade_state = Column(String(255)) + vnics_used = Column(Integer) + hostname = Column(String(255)) + dynamic_vnics = relation(DynamicVnic, order_by=DynamicVnic.uuid, + backref="blade") + + def __init__(self, mgmt_ip, mac_addr, chassis_id, ucsm_ip, + blade_state, vnics_used, hostname): + self.uuid = uuid.uuid4() + self.mgmt_ip = mgmt_ip + self.mac_addr = mac_addr + self.chassis_id = chassis_id + self.ucsm_ip = ucsm_ip + self.blade_state = blade_state + self.vnics_used = vnics_used + self.hostname = hostname + + def __repr__(self): + return "" % \ + (self.uuid, self.mgmt_ip, self.mac_addr, self.chassis_id, + self.ucsm_ip, self.blade_state, self.vnics_used, self.hostname) + + +class PortBinding(BASE, L2NetworkBase): + """Represents Port binding to device interface""" + __tablename__ = 'port_bindings' + + id = Column(Integer, primary_key=True, autoincrement=True) + port_id = Column(String(255), ForeignKey("ports.uuid"), + nullable=False) + dynamic_vnic_id = Column(String(255), ForeignKey("dynamic_vnics.uuid"), + nullable=False) + portprofile_name = Column(String(255)) + vlan_name = Column(String(255)) + vlan_id = Column(Integer) + qos = Column(String(255)) + ports = relation(models.Port, uselist=False) + dynamic_vnics = relation(DynamicVnic, uselist=False) + + def __init__(self, port_id, dynamic_vnic_id, portprofile_name, + vlan_name, vlan_id, qos): + self.port_id = port_id + self.dynamic_vnic_id = dynamic_vnic_id + self.portprofile_name = portprofile_name + self.vlan_name = vlan_name + self.vlan_id = vlan_id + self.qos = qos + + def __repr__(self): + return "" % \ + (self.port_id, self.dynamic_vnic_id, self.portprofile_name, + self.vlan_name, self.vlan_id, self.qos) diff --git a/quantum/plugins/cisco/tests/unit/test_database.py b/quantum/plugins/cisco/tests/unit/test_database.py index 2ae7f0271f..d97592b560 100644 --- a/quantum/plugins/cisco/tests/unit/test_database.py +++ b/quantum/plugins/cisco/tests/unit/test_database.py @@ -27,11 +27,328 @@ from quantum.plugins.cisco.common import cisco_constants as const import quantum.plugins.cisco.db.api as db import quantum.plugins.cisco.db.l2network_db as l2network_db import quantum.plugins.cisco.db.nexus_db as nexus_db +import quantum.plugins.cisco.db.ucs_db as ucs_db LOG.getLogger(const.LOGGER_COMPONENT_NAME) +class UcsDB(object): + """Class consisting of methods to call ucs db methods""" + def get_all_ucsmbindings(self): + """get all ucsm bindings""" + bindings = [] + try: + for res in ucs_db.get_all_ucsmbinding(): + LOG.debug("Getting ucsm binding : %s" % res.ucsm_ip) + bind_dict = {} + bind_dict["ucsm-ip"] = str(res.ucsm_ip) + bind_dict["network-id"] = str(res.network_id) + bindings.append(bind_dict) + except Exception, exc: + LOG.error("Failed to get all bindings: %s" % str(exc)) + return bindings + + def get_ucsmbinding(self, ucsm_ip): + """get ucsm binding""" + binding = [] + try: + for res in ucs_db.get_ucsmbinding(ucsm_ip): + LOG.debug("Getting ucsm binding : %s" % res.ucsm_ip) + bind_dict = {} + bind_dict["ucsm-ip"] = str(res.ucsm_ip) + bind_dict["network-id"] = str(res.network_id) + binding.append(bind_dict) + except Exception, exc: + LOG.error("Failed to get binding: %s" % str(exc)) + return binding + + def create_ucsmbinding(self, ucsm_ip, network_id): + """create ucsm binding""" + bind_dict = {} + try: + res = ucs_db.add_ucsmbinding(ucsm_ip, network_id) + LOG.debug("Created ucsm binding: %s" % res.ucsm_ip) + bind_dict["ucsm-ip"] = str(res.ucsm_ip) + bind_dict["network-id"] = str(res.network_id) + return bind_dict + except Exception, exc: + LOG.error("Failed to create ucsm binding: %s" % str(exc)) + + def delete_ucsmbinding(self, ucsm_ip): + """delete ucsm binding""" + try: + res = ucs_db.remove_ucsmbinding(ucsm_ip) + LOG.debug("Deleted ucsm binding : %s" % res.ucsm_ip) + bind_dict = {} + bind_dict["ucsm-ip"] = str(res.ucsm_ip) + return bind_dict + except Exception, exc: + raise Exception("Failed to delete dynamic vnic: %s" % str(exc)) + + def update_ucsmbinding(self, ucsm_ip, network_id): + """update ucsm binding""" + try: + res = ucs_db.update_ucsmbinding(ucsm_ip, network_id) + LOG.debug("Updating ucsm binding : %s" % res.ucsm_ip) + bind_dict = {} + bind_dict["ucsm-ip"] = str(res.ucsm_ip) + bind_dict["network-id"] = str(res.network_id) + return bind_dict + except Exception, exc: + raise Exception("Failed to update dynamic vnic: %s" % str(exc)) + + def get_all_dynamicvnics(self): + """get all dynamic vnics""" + vnics = [] + try: + for res in ucs_db.get_all_dynamicvnics(): + LOG.debug("Getting dynamic vnic : %s" % res.uuid) + vnic_dict = {} + vnic_dict["vnic-id"] = str(res.uuid) + vnic_dict["device-name"] = res.device_name + vnic_dict["blade-id"] = str(res.blade_id) + vnic_dict["vnic_state"] = res.vnic_state + vnics.append(vnic_dict) + except Exception, exc: + LOG.error("Failed to get all dynamic vnics: %s" % str(exc)) + return vnics + + def get_dynamicvnic(self, vnic_id): + """get dynamic vnic""" + vnic = [] + try: + for res in ucs_db.get_dynamicvnic(vnic_id): + LOG.debug("Getting dynamic vnic : %s" % res.uuid) + vnic_dict = {} + vnic_dict["vnic-id"] = str(res.uuid) + vnic_dict["device-name"] = res.device_name + vnic_dict["blade-id"] = str(res.blade_id) + vnic_dict["vnic_state"] = res.vnic_state + vnic.append(vnic_dict) + except Exception, exc: + LOG.error("Failed to get dynamic vnic: %s" % str(exc)) + return vnic + + def create_dynamicvnic(self, device_name, blade_id, vnic_state): + """create dynamic vnic""" + vnic_dict = {} + try: + res = ucs_db.add_dynamicvnic(device_name, blade_id, vnic_state) + LOG.debug("Created dynamic vnic: %s" % res.uuid) + vnic_dict["vnic-id"] = str(res.uuid) + vnic_dict["device-name"] = res.device_name + vnic_dict["blade-id"] = str(res.blade_id) + vnic_dict["vnic_state"] = res.vnic_state + return vnic_dict + except Exception, exc: + LOG.error("Failed to create dynamic vnic: %s" % str(exc)) + + def delete_dynamicvnic(self, vnic_id): + """delete dynamic vnic""" + try: + res = ucs_db.remove_dynamicvnic(vnic_id) + LOG.debug("Deleted dynamic vnic : %s" % res.uuid) + vnic_dict = {} + vnic_dict["vnic-id"] = str(res.uuid) + return vnic_dict + except Exception, exc: + raise Exception("Failed to delete dynamic vnic: %s" % str(exc)) + + def update_dynamicvnic(self, vnic_id, device_name=None, blade_id=None, + vnic_state=None): + """update dynamic vnic""" + try: + res = ucs_db.update_dynamicvnic(vnic_id, device_name, blade_id, + vnic_state) + LOG.debug("Updating dynamic vnic : %s" % res.uuid) + vnic_dict = {} + vnic_dict["vnic-id"] = str(res.uuid) + vnic_dict["device-name"] = res.device_name + vnic_dict["blade-id"] = str(res.blade_id) + vnic_dict["vnic_state"] = res.vnic_state + return vnic_dict + except Exception, exc: + raise Exception("Failed to update dynamic vnic: %s" % str(exc)) + + def get_all_blades(self): + """get all blades""" + blades = [] + try: + for res in ucs_db.get_all_blades(): + LOG.debug("Getting blade : %s" % res.uuid) + blade_dict = {} + blade_dict["blade-id"] = str(res.uuid) + blade_dict["mgmt-ip"] = str(res.mgmt_ip) + blade_dict["mac-addr"] = str(res.mac_addr) + blade_dict["chassis-id"] = str(res.chassis_id) + blade_dict["ucsm-ip"] = str(res.ucsm_ip) + blade_dict["blade_state"] = str(res.blade_state) + blade_dict["vnics_used"] = str(res.vnics_used) + blade_dict["hostname"] = str(res.hostname) + blades.append(blade_dict) + except Exception, exc: + LOG.error("Failed to get all blades: %s" % str(exc)) + return blades + + def get_blade(self, blade_id): + """get blade""" + blade = [] + try: + for res in ucs_db.get_blade(blade_id): + LOG.debug("Getting blade : %s" % res.uuid) + blade_dict = {} + blade_dict["blade-id"] = str(res.uuid) + blade_dict["mgmt-ip"] = str(res.mgmt_ip) + blade_dict["mac-addr"] = str(res.mac_addr) + blade_dict["chassis-id"] = str(res.chassis_id) + blade_dict["ucsm-ip"] = str(res.ucsm_ip) + blade_dict["blade_state"] = str(res.blade_state) + blade_dict["vnics_used"] = str(res.vnics_used) + blade_dict["hostname"] = str(res.hostname) + blade.append(blade_dict) + except Exception, exc: + LOG.error("Failed to get all blades: %s" % str(exc)) + return blade + + def create_blade(self, mgmt_ip, mac_addr, chassis_id, ucsm_ip, + blade_state, vnics_used, hostname): + """create blade""" + blade_dict = {} + try: + res = ucs_db.add_blade(mgmt_ip, mac_addr, chassis_id, ucsm_ip, + blade_state, vnics_used, hostname) + LOG.debug("Created blade: %s" % res.uuid) + blade_dict["blade-id"] = str(res.uuid) + blade_dict["mgmt-ip"] = str(res.mgmt_ip) + blade_dict["mac-addr"] = str(res.mac_addr) + blade_dict["chassis-id"] = str(res.chassis_id) + blade_dict["ucsm-ip"] = str(res.ucsm_ip) + blade_dict["blade_state"] = str(res.blade_state) + blade_dict["vnics_used"] = str(res.vnics_used) + blade_dict["hostname"] = str(res.hostname) + return blade_dict + except Exception, exc: + LOG.error("Failed to create blade: %s" % str(exc)) + + def delete_blade(self, blade_id): + """delete blade""" + try: + res = ucs_db.remove_blade(blade_id) + LOG.debug("Deleted blade : %s" % res.uuid) + blade_dict = {} + blade_dict["blade-id"] = str(res.uuid) + return blade_dict + except Exception, exc: + raise Exception("Failed to delete blade: %s" % str(exc)) + + def update_blade(self, blade_id, mgmt_ip=None, mac_addr=None, + chassis_id=None, ucsm_ip=None, blade_state=None, + vnics_used=None, hostname=None): + """update blade""" + try: + res = ucs_db.update_blade(blade_id, mgmt_ip, mac_addr, + chassis_id, ucsm_ip, blade_state, + vnics_used, hostname) + LOG.debug("Updating blade : %s" % res.uuid) + blade_dict = {} + blade_dict["blade-id"] = str(res.uuid) + blade_dict["mgmt-ip"] = str(res.mgmt_ip) + blade_dict["mac-addr"] = str(res.mac_addr) + blade_dict["chassis-id"] = str(res.chassis_id) + blade_dict["ucsm-ip"] = str(res.ucsm_ip) + blade_dict["blade_state"] = str(res.blade_state) + blade_dict["vnics_used"] = str(res.vnics_used) + blade_dict["hostname"] = str(res.hostname) + return blade_dict + except Exception, exc: + raise Exception("Failed to update blade: %s" % str(exc)) + + def get_all_port_bindings(self): + """get all port binding""" + port_bindings = [] + try: + for bind in ucs_db.get_all_portbindings(): + LOG.debug("Getting port binding for port: %s" % bind.port_id) + port_bind_dict = {} + port_bind_dict["port-id"] = bind.port_id + port_bind_dict["dynamic-vnic-id"] = str(bind.dynamic_vnic_id) + port_bind_dict["portprofile-name"] = bind.portprofile_name + port_bind_dict["vlan-name"] = bind.vlan_name + port_bind_dict["vlan-id"] = str(bind.vlan_id) + port_bind_dict["qos"] = bind.qos + port_bindings.append(port_bind_dict) + except Exception, exc: + LOG.error("Failed to get all port bindings: %s" % str(exc)) + return port_bindings + + def get_port_binding(self, port_id): + """get port binding""" + port_binding = [] + try: + for bind in ucs_db.get_portbinding(port_id): + LOG.debug("Getting port binding for port: %s" % bind.port_id) + port_bind_dict = {} + port_bind_dict["port-id"] = bind.port_id + port_bind_dict["dynamic-vnic-id"] = str(bind.dynamic_vnic_id) + port_bind_dict["portprofile-name"] = bind.portprofile_name + port_bind_dict["vlan-name"] = bind.vlan_name + port_bind_dict["vlan-id"] = str(bind.vlan_id) + port_bind_dict["qos"] = bind.qos + port_binding.append(port_bind_dict) + except Exception, exc: + LOG.error("Failed to get port binding: %s" % str(exc)) + return port_binding + + def create_port_binding(self, port_id, dynamic_vnic_id, portprofile_name, \ + vlan_name, vlan_id, qos): + """create port binding""" + port_bind_dict = {} + try: + res = ucs_db.add_portbinding(port_id, dynamic_vnic_id, \ + portprofile_name, vlan_name, vlan_id, qos) + LOG.debug("Created port binding: %s" % res.port_id) + port_bind_dict["port-id"] = res.port_id + port_bind_dict["dynamic-vnic-id"] = str(res.dynamic_vnic_id) + port_bind_dict["portprofile-name"] = res.portprofile_name + port_bind_dict["vlan-name"] = res.vlan_name + port_bind_dict["vlan-id"] = str(res.vlan_id) + port_bind_dict["qos"] = res.qos + return port_bind_dict + except Exception, exc: + LOG.error("Failed to create port binding: %s" % str(exc)) + + def delete_port_binding(self, port_id): + """delete port binding""" + try: + res = ucs_db.remove_portbinding(port_id) + LOG.debug("Deleted port binding : %s" % res.port_id) + port_bind_dict = {} + port_bind_dict["port-id"] = res.port_id + return port_bind_dict + except Exception, exc: + raise Exception("Failed to delete port profile: %s" % str(exc)) + + def update_port_binding(self, port_id, dynamic_vnic_id, \ + portprofile_name, vlan_name, vlan_id, qos): + """update port binding""" + try: + res = ucs_db.update_portbinding(port_id, dynamic_vnic_id, \ + portprofile_name, vlan_name, vlan_id, qos) + LOG.debug("Updating port binding: %s" % res.port_id) + port_bind_dict = {} + port_bind_dict["port-id"] = res.port_id + port_bind_dict["dynamic-vnic-id"] = str(res.dynamic_vnic_id) + port_bind_dict["portprofile-name"] = res.portprofile_name + port_bind_dict["vlan-name"] = res.vlan_name + port_bind_dict["vlan-id"] = str(res.vlan_id) + port_bind_dict["qos"] = res.qos + return port_bind_dict + except Exception, exc: + raise Exception("Failed to update portprofile binding:%s" + % str(exc)) + + class NexusDB(object): """Class consisting of methods to call nexus db methods""" def get_all_nexusportbindings(self): @@ -110,7 +427,7 @@ class L2networkDB(object): vlans = [] try: for vlan_bind in l2network_db.get_all_vlan_bindings(): - LOG.debug("Getting vlan bindings for vlan: %s" % \ + LOG.debug("Getting vlan bindings for vlan: %s" % vlan_bind.vlan_id) vlan_dict = {} vlan_dict["vlan-id"] = str(vlan_bind.vlan_id) @@ -126,7 +443,7 @@ class L2networkDB(object): vlan = [] try: for vlan_bind in l2network_db.get_vlan_binding(network_id): - LOG.debug("Getting vlan binding for vlan: %s" \ + LOG.debug("Getting vlan binding for vlan: %s" % vlan_bind.vlan_id) vlan_dict = {} vlan_dict["vlan-id"] = str(vlan_bind.vlan_id) @@ -164,7 +481,7 @@ class L2networkDB(object): def update_vlan_binding(self, network_id, vlan_id, vlan_name): """Update a vlan binding""" try: - res = l2network_db.update_vlan_binding(network_id, vlan_id, \ + res = l2network_db.update_vlan_binding(network_id, vlan_id, vlan_name) LOG.debug("Updating vlan binding for vlan: %s" % res.vlan_id) vlan_dict = {} @@ -252,7 +569,7 @@ class L2networkDB(object): pp_bindings = [] try: for pp_bind in l2network_db.get_all_pp_bindings(): - LOG.debug("Getting port profile binding: %s" % \ + LOG.debug("Getting port profile binding: %s" % pp_bind.portprofile_id) ppbinding_dict = {} ppbinding_dict["portprofile-id"] = str(pp_bind.portprofile_id) @@ -269,7 +586,7 @@ class L2networkDB(object): pp_binding = [] try: for pp_bind in l2network_db.get_pp_binding(tenant_id, pp_id): - LOG.debug("Getting port profile binding: %s" % \ + LOG.debug("Getting port profile binding: %s" % pp_bind.portprofile_id) ppbinding_dict = {} ppbinding_dict["portprofile-id"] = str(pp_bind.portprofile_id) @@ -285,7 +602,7 @@ class L2networkDB(object): """Add a portprofile binding""" ppbinding_dict = {} try: - res = l2network_db.add_pp_binding(tenant_id, port_id, pp_id, \ + res = l2network_db.add_pp_binding(tenant_id, port_id, pp_id, default) LOG.debug("Created port profile binding: %s" % res.portprofile_id) ppbinding_dict["portprofile-id"] = str(res.portprofile_id) @@ -307,7 +624,7 @@ class L2networkDB(object): except Exception, exc: raise Exception("Failed to delete port profile: %s" % str(exc)) - def update_pp_binding(self, tenant_id, pp_id, newtenant_id, \ + def update_pp_binding(self, tenant_id, pp_id, newtenant_id, port_id, default): """Update portprofile binding""" try: @@ -321,7 +638,7 @@ class L2networkDB(object): ppbinding_dict["default"] = res.default return ppbinding_dict except Exception, exc: - raise Exception("Failed to update portprofile binding:%s" \ + raise Exception("Failed to update portprofile binding:%s" % str(exc)) @@ -494,6 +811,317 @@ class QuantumDB(object): raise Exception("Failed to unplug interface: %s" % str(exc)) +class UcsDBTest(unittest.TestCase): + """Class conisting of ucs DB unit tests""" + def setUp(self): + """Setup for ucs db tests""" + l2network_db.initialize() + self.quantum = QuantumDB() + self.dbtest = UcsDB() + LOG.debug("Setup") + + def tearDown(self): + """Tear Down""" + db.clear_db() + + def testa_create_ucsmbinding(self): + """create ucsm binding""" + net1 = self.quantum.create_network("t1", "netid1") + binding1 = self.dbtest.create_ucsmbinding("1.2.3.4", net1["net-id"]) + self.assertTrue(binding1["ucsm-ip"] == "1.2.3.4") + self.teardown_ucsmbinding() + self.teardown_network() + + def testb_getall_ucsmbindings(self): + """get all ucsm bindings""" + net1 = self.quantum.create_network("t1", "netid1") + binding1 = self.dbtest.create_ucsmbinding("1.2.3.4", net1["net-id"]) + binding2 = self.dbtest.create_ucsmbinding("2.3.4.5", net1["net-id"]) + bindings = self.dbtest.get_all_ucsmbindings() + count = 0 + for bind in bindings: + if net1["net-id"] == bind["network-id"]: + count += 1 + self.assertTrue(count == 2) + self.teardown_ucsmbinding() + self.teardown_network() + + def testc_delete_ucsmbinding(self): + """delete ucsm binding""" + net1 = self.quantum.create_network("t1", "netid1") + binding1 = self.dbtest.create_ucsmbinding("1.2.3.4", net1["net-id"]) + self.dbtest.delete_ucsmbinding(binding1["ucsm-ip"]) + bindings = self.dbtest.get_all_ucsmbindings() + count = 0 + for bind in bindings: + if "net " in bind["network-id"]: + count += 1 + self.assertTrue(count == 0) + self.teardown_ucsmbinding() + self.teardown_network() + + def testd_update_ucsmbinding(self): + """update ucsm binding""" + net1 = self.quantum.create_network("t1", "netid1") + net2 = self.quantum.create_network("t1", "netid2") + binding1 = self.dbtest.create_ucsmbinding("1.2.3.4", net1["net-id"]) + binding1 = self.dbtest.update_ucsmbinding(binding1["ucsm-ip"], + net2["net-id"]) + bindings = self.dbtest.get_all_ucsmbindings() + count = 0 + for bind in bindings: + if net2["net-id"] == bind["network-id"]: + count += 1 + self.assertTrue(count == 1) + self.teardown_ucsmbinding() + self.teardown_network() + + def teste_create_dynamicvnic(self): + """create dynamic vnic""" + blade1 = self.dbtest.create_blade("1.2.3.4", "abcd", "chassis1", + "9.8.7.6", "UP", 2, "blade1") + vnic1 = self.dbtest.create_dynamicvnic("eth1", blade1["blade-id"], + "UP") + self.assertTrue(vnic1["device-name"] == "eth1") + self.teardown_dyanmicvnic() + + def testf_getall_dyanmicvnics(self): + """get all dynamic vnics""" + blade1 = self.dbtest.create_blade("1.2.3.4", "abcd", "chassis1", + "9.8.7.6", "UP", 2, "blade1") + vnic1 = self.dbtest.create_dynamicvnic("eth1", blade1["blade-id"], + "UP") + vnic2 = self.dbtest.create_dynamicvnic("eth2", blade1["blade-id"], + "UP") + vnics = self.dbtest.get_all_dynamicvnics() + count = 0 + for vnic in vnics: + if "eth" in vnic["device-name"]: + count += 1 + self.assertTrue(count == 2) + self.teardown_dyanmicvnic() + + def testg_delete_dyanmicvnic(self): + """delete dynamic vnic""" + blade1 = self.dbtest.create_blade("1.2.3.4", "abcd", "chassis1", + "9.8.7.6", "UP", 2, "blade1") + vnic1 = self.dbtest.create_dynamicvnic("eth1", blade1["blade-id"], + "UP") + self.dbtest.delete_dynamicvnic(vnic1["vnic-id"]) + vnics = self.dbtest.get_all_dynamicvnics() + count = 0 + for vnic in vnics: + if "eth " in vnic["device-name"]: + count += 1 + self.assertTrue(count == 0) + self.teardown_dyanmicvnic() + + def testh_updatedynamicvnic(self): + """update dynamic vnic""" + blade1 = self.dbtest.create_blade("1.2.3.4", "abcd", "chassis1", + "9.8.7.6", "UP", 2, "blade1") + vnic1 = self.dbtest.create_dynamicvnic("eth1", blade1["blade-id"], + "UP") + vnic1 = self.dbtest.update_dynamicvnic(vnic1["vnic-id"], "neweth1", + blade1["blade-id"], "DOWN") + vnics = self.dbtest.get_all_dynamicvnics() + count = 0 + for vnic in vnics: + if "new" in vnic["device-name"]: + count += 1 + self.assertTrue(count == 1) + self.teardown_dyanmicvnic() + + def testi_create_ucsblade(self): + """create ucs blade""" + blade1 = self.dbtest.create_blade("1.2.3.4", "abcd", "chassis1", + "9.8.7.6", "UP", 2, "blade1") + self.assertTrue(blade1["mgmt-ip"] == "1.2.3.4") + self.teardown_ucsblade() + + def testj_getall_ucsblade(self): + """get all ucs blades""" + blade1 = self.dbtest.create_blade("1.2.3.4", "abcd", "chassis1", + "9.8.7.6", "UP", 2, "blade1") + blade2 = self.dbtest.create_blade("2.3.4.5", "efgh", "chassis1", + "9.8.7.6", "UP", 3, "blade2") + blades = self.dbtest.get_all_blades() + count = 0 + for blade in blades: + if "chassis" in blade["chassis-id"]: + count += 1 + self.assertTrue(count == 2) + self.teardown_ucsblade() + + def testk_delete_ucsblade(self): + """delete ucs blades""" + blade1 = self.dbtest.create_blade("1.2.3.4", "abcd", "chassis1", + "9.8.7.6", "UP", 2, "blade1") + self.dbtest.delete_blade(blade1["blade-id"]) + blades = self.dbtest.get_all_blades() + count = 0 + for blade in blades: + if "chassis " in blade["chassis-id"]: + count += 1 + self.assertTrue(count == 0) + self.teardown_ucsblade() + + def testl_update_ucsblade(self): + """update ucs blade""" + blade1 = self.dbtest.create_blade("1.2.3.4", "abcd", "chassis1", + "9.8.7.6", "UP", 2, "blade1") + blade2 = self.dbtest.update_blade(blade1["blade-id"], "2.3.4.5", + "newabcd", "chassis1", "9.8.7.6", + "UP", 3, "blade1") + blades = self.dbtest.get_all_blades() + count = 0 + for blade in blades: + if "new" in blade["mac-addr"]: + count += 1 + self.assertTrue(count == 1) + self.teardown_ucsblade() + + def testm_create_portbinding(self): + """create port binding""" + net1 = self.quantum.create_network("t1", "netid1") + port1 = self.quantum.create_port(net1["net-id"]) + blade1 = self.dbtest.create_blade("1.2.3.4", "abcd", "chassis1", + "9.8.7.6", "UP", 2, "blade1") + vnic1 = self.dbtest.create_dynamicvnic("eth1", blade1["blade-id"], + "UP") + port_bind1 = self.dbtest.create_port_binding(port1["port-id"], + vnic1["vnic-id"], "pp1", "vlan1", 10, "qos1") + self.assertTrue(port_bind1["port-id"] == port1["port-id"]) + self.teardown_portbinding() + self.teardown_dyanmicvnic() + self.teardown_ucsblade() + self.teardown_network_port() + + def testn_getall_portbindings(self): + """get all port binding""" + net1 = self.quantum.create_network("t1", "netid1") + port1 = self.quantum.create_port(net1["net-id"]) + port2 = self.quantum.create_port(net1["net-id"]) + blade1 = self.dbtest.create_blade("1.2.3.4", "abcd", "chassis1", + "9.8.7.6", "UP", 2, "blade1") + vnic1 = self.dbtest.create_dynamicvnic("eth1", blade1["blade-id"], + "UP") + vnic2 = self.dbtest.create_dynamicvnic("eth2", blade1["blade-id"], + "UP") + port_bind1 = self.dbtest.create_port_binding(port1["port-id"], + vnic1["vnic-id"], "pp1", "vlan1", 10, "qos1") + port_bind2 = self.dbtest.create_port_binding(port2["port-id"], + vnic2["vnic-id"], "pp2", "vlan2", 20, "qos2") + port_bindings = self.dbtest.get_all_port_bindings() + count = 0 + for pbind in port_bindings: + if "vlan" in pbind["vlan-name"]: + count += 1 + self.assertTrue(count == 2) + self.teardown_portbinding() + self.teardown_dyanmicvnic() + self.teardown_ucsblade() + self.teardown_network_port() + + def testo_delete_portbinding(self): + """delete port binding""" + net1 = self.quantum.create_network("t1", "netid1") + port1 = self.quantum.create_port(net1["net-id"]) + blade1 = self.dbtest.create_blade("1.2.3.4", "abcd", "chassis1", + "9.8.7.6", "UP", 2, "blade1") + vnic1 = self.dbtest.create_dynamicvnic("eth1", blade1["blade-id"], + "UP") + port_bind1 = self.dbtest.create_port_binding(port1["port-id"], + vnic1["vnic-id"], "pp1", "vlan1", 10, "qos1") + self.dbtest.delete_port_binding(port1["port-id"]) + port_bindings = self.dbtest.get_all_port_bindings() + count = 0 + for pbind in port_bindings: + if "vlan " in pbind["vlan-name"]: + count += 1 + self.assertTrue(count == 0) + self.teardown_portbinding() + self.teardown_dyanmicvnic() + self.teardown_ucsblade() + self.teardown_network_port() + + def testp_update_portbinding(self): + """update port binding""" + net1 = self.quantum.create_network("t1", "netid1") + port1 = self.quantum.create_port(net1["net-id"]) + blade1 = self.dbtest.create_blade("1.2.3.4", "abcd", "chassis1", + "9.8.7.6", "UP", 2, "blade1") + vnic1 = self.dbtest.create_dynamicvnic("eth1", blade1["blade-id"], + "UP") + port_bind1 = self.dbtest.create_port_binding(port1["port-id"], + vnic1["vnic-id"], "pp1", "vlan1", 10, "qos1") + port_bind1 = self.dbtest.update_port_binding(port1["port-id"], + vnic1["vnic-id"], "newpp1", "newvlan1", 11, "newqos1") + port_bindings = self.dbtest.get_all_port_bindings() + count = 0 + for pbind in port_bindings: + if "new" in pbind["vlan-name"]: + count += 1 + self.assertTrue(count == 1) + self.teardown_portbinding() + self.teardown_dyanmicvnic() + self.teardown_ucsblade() + self.teardown_network_port() + + def teardown_ucsmbinding(self): + """tear down ucsm binding""" + LOG.debug("Tearing Down Ucsm Bindings") + binds = self.dbtest.get_all_ucsmbindings() + for bind in binds: + ucsmip = bind["ucsm-ip"] + self.dbtest.delete_ucsmbinding(ucsmip) + + def teardown_dyanmicvnic(self): + """tear down dynamic vnics""" + LOG.debug("Tearing Down Dynamic Vnics") + vnics = self.dbtest.get_all_dynamicvnics() + for vnic in vnics: + vnicid = vnic["vnic-id"] + self.dbtest.delete_dynamicvnic(vnicid) + self.teardown_ucsblade() + + def teardown_ucsblade(self): + """tear down ucs blades""" + LOG.debug("Tearing Down Blades") + blades = self.dbtest.get_all_blades() + for blade in blades: + bladeid = blade["blade-id"] + self.dbtest.delete_blade(bladeid) + + def teardown_portbinding(self): + """tear down port binding""" + LOG.debug("Tearing Down Port Binding") + port_bindings = self.dbtest.get_all_port_bindings() + for port_binding in port_bindings: + portid = port_binding["port-id"] + self.dbtest.delete_port_binding(portid) + + def teardown_network(self): + """tearDown Network table""" + LOG.debug("Tearing Down Network") + nets = self.quantum.get_all_networks("t1") + for net in nets: + netid = net["net-id"] + self.quantum.delete_network(netid) + + def teardown_network_port(self): + """tearDown for Network and Port table""" + networks = self.quantum.get_all_networks("t1") + for net in networks: + netid = net["net-id"] + name = net["net-name"] + if "net" in name: + ports = self.quantum.get_all_ports(netid) + for por in ports: + self.quantum.delete_port(netid, por["port-id"]) + self.quantum.delete_network(netid) + + class NexusDBTest(unittest.TestCase): """Class conisting of nexus DB unit tests""" def setUp(self): From 764eca55d1b206c3c3af3fb69734965dbe23d0bd Mon Sep 17 00:00:00 2001 From: Sumit Naiksatam Date: Sat, 20 Aug 2011 12:44:23 -0700 Subject: [PATCH 07/39] adding utility functions to create dictionaries --- quantum/plugins/cisco/common/cisco_utils.py | 40 +++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/quantum/plugins/cisco/common/cisco_utils.py b/quantum/plugins/cisco/common/cisco_utils.py index 58b62bd543..b5e70623b6 100644 --- a/quantum/plugins/cisco/common/cisco_utils.py +++ b/quantum/plugins/cisco/common/cisco_utils.py @@ -26,6 +26,8 @@ import traceback from quantum.plugins.cisco.common import cisco_constants as const from quantum.plugins.cisco.common import cisco_nova_configuration as conf +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) @@ -39,6 +41,44 @@ def get16ByteUUID(uuid): return hashlib.md5(uuid).hexdigest()[:16] +def make_net_dict(net_id, net_name, ports): + """Helper funciton""" + res = {const.NET_ID: net_id, const.NET_NAME: net_name} + res[const.NET_PORTS] = ports + return res + + +def make_port_dict(port_id, port_state, net_id, attachment): + """Helper funciton""" + res = {const.PORT_ID: port_id, const.PORT_STATE: port_state} + res[const.NET_ID] = net_id + res[const.ATTACHMENT] = attachment + return res + + +def make_portprofile_dict(tenant_id, profile_id, profile_name, + qos): + """Helper funciton""" + profile_associations = make_portprofile_assc_list(tenant_id, + profile_id) + res = {const.PROFILE_ID: str(profile_id), + const.PROFILE_NAME: profile_name, + const.PROFILE_ASSOCIATIONS: profile_associations, + const.PROFILE_VLAN_ID: None, + const.PROFILE_QOS: qos} + return res + + +def make_portprofile_assc_list(tenant_id, profile_id): + """Helper function to create port profile association list""" + plist = cdb.get_pp_binding(tenant_id, profile_id) + assc_list = [] + for port in plist: + assc_list.append(port[const.PORTID]) + + return assc_list + + class DBUtils(object): """Utilities to use connect to MySQL DB and execute queries""" From 4ba67cea7163ed1bbb51030da8f0ebaa5ccb3ea2 Mon Sep 17 00:00:00 2001 From: Sumit Naiksatam Date: Sat, 20 Aug 2011 13:45:17 -0700 Subject: [PATCH 08/39] Persistence support for UCS plugin network. --- quantum/plugins/cisco/ucs/cisco_ucs_plugin.py | 92 ++++++++++++------- 1 file changed, 60 insertions(+), 32 deletions(-) diff --git a/quantum/plugins/cisco/ucs/cisco_ucs_plugin.py b/quantum/plugins/cisco/ucs/cisco_ucs_plugin.py index 87efa684cf..7545ef898c 100644 --- a/quantum/plugins/cisco/ucs/cisco_ucs_plugin.py +++ b/quantum/plugins/cisco/ucs/cisco_ucs_plugin.py @@ -27,6 +27,8 @@ from quantum.plugins.cisco.common import cisco_constants as const from quantum.plugins.cisco.common import cisco_credentials as cred from quantum.plugins.cisco.common import cisco_exceptions as cexc 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 from quantum.plugins.cisco.l2device_plugin_base import L2DevicePluginBase from quantum.plugins.cisco.ucs import cisco_ucs_configuration as conf @@ -39,7 +41,7 @@ class UCSVICPlugin(L2DevicePluginBase): _networks = {} def __init__(self): - self._client = utils.import_object(conf.UCSM_DRIVER) + self._driver = utils.import_object(conf.UCSM_DRIVER) LOG.debug("Loaded driver %s\n" % conf.UCSM_DRIVER) # TODO (Sumit) Make the counter per UCSM self._port_profile_counter = 0 @@ -52,7 +54,15 @@ class UCSVICPlugin(L2DevicePluginBase): """ LOG.debug("UCSVICPlugin:get_all_networks() called\n") self._set_ucsm(kwargs[const.DEVICE_IP]) - return self._networks.values() + networks_list = db.network_list(tenant_id) + new_networks_list = [] + for network in networks_list: + new_network_dict = cutil.make_net_dict(network[const.UUID], + network[const.NETWORKNAME], + []) + new_networks_list.append(new_network_dict) + + return new_networks_list def create_network(self, tenant_id, net_name, net_id, vlan_name, vlan_id, **kwargs): @@ -62,15 +72,14 @@ class UCSVICPlugin(L2DevicePluginBase): """ LOG.debug("UCSVICPlugin:create_network() called\n") self._set_ucsm(kwargs[const.DEVICE_IP]) - self._client.create_vlan(vlan_name, str(vlan_id), self._ucsm_ip, + self._driver.create_vlan(vlan_name, str(vlan_id), self._ucsm_ip, self._ucsm_username, self._ucsm_password) - new_net_dict = {const.NET_ID: net_id, - const.NET_NAME: net_name, - const.NET_PORTS: {}, - const.NET_VLAN_NAME: vlan_name, - const.NET_VLAN_ID: vlan_id} - self._networks[net_id] = new_net_dict - return new_net_dict + network = db.network_get(net_id) + ports_on_net = [] + new_network_dict = cutil.make_net_dict(network[const.UUID], + network[const.NETWORKNAME], + ports_on_net) + return new_network_dict def delete_network(self, tenant_id, net_id, **kwargs): """ @@ -79,17 +88,13 @@ class UCSVICPlugin(L2DevicePluginBase): """ LOG.debug("UCSVICPlugin:delete_network() called\n") self._set_ucsm(kwargs[const.DEVICE_IP]) - net = self._networks.get(net_id) - # TODO (Sumit) : Verify that no attachments are plugged into the - # network - if net: - # TODO (Sumit) : Before deleting the network, make sure all the - # ports associated with this network are also deleted - self._client.delete_vlan(net[const.NET_VLAN_NAME], self._ucsm_ip, - self._ucsm_username, self._ucsm_password) - self._networks.pop(net_id) - return net - raise exc.NetworkNotFound(net_id=net_id) + net = db.network_get(net_id) + self._driver.delete_vlan(net[const.NET_VLAN_NAME], self._ucsm_ip, + self._ucsm_username, self._ucsm_password) + net_dict = cutil.make_net_dict(net[const.UUID], + net[const.NETWORKNAME], + []) + return net_dict def get_network_details(self, tenant_id, net_id, **kwargs): """ @@ -98,8 +103,21 @@ class UCSVICPlugin(L2DevicePluginBase): """ LOG.debug("UCSVICPlugin:get_network_details() called\n") self._set_ucsm(kwargs[const.DEVICE_IP]) - network = self._get_network(tenant_id, net_id) - return network + network = db.network_get(net_id) + ports_list = network[const.NETWORKPORTS] + ports_on_net = [] + for port in ports_list: + new_port = cutil.make_port_dict(port[const.UUID], + port[const.PORTSTATE], + port[const.NETWORKID], + port[const.INTERFACEID]) + ports_on_net.append(new_port) + + new_network = cutil.make_net_dict(network[const.UUID], + network[const.NETWORKNAME], + ports_on_net) + + return new_network def rename_network(self, tenant_id, net_id, new_name, **kwargs): """ @@ -108,9 +126,11 @@ class UCSVICPlugin(L2DevicePluginBase): """ LOG.debug("UCSVICPlugin:rename_network() called\n") self._set_ucsm(kwargs[const.DEVICE_IP]) - network = self._get_network(tenant_id, net_id) - network[const.NET_NAME] = new_name - return network + network = db.network_get(net_id) + net_dict = cutil.make_net_dict(network[const.UUID], + network[const.NETWORKNAME], + []) + return net_dict def get_all_ports(self, tenant_id, net_id, **kwargs): """ @@ -119,8 +139,16 @@ class UCSVICPlugin(L2DevicePluginBase): """ LOG.debug("UCSVICPlugin:get_all_ports() called\n") self._set_ucsm(kwargs[const.DEVICE_IP]) - network = self._get_network(tenant_id, net_id) - ports_on_net = network[const.NET_PORTS].values() + network = db.network_get(net_id) + ports_list = network[const.NETWORKPORTS] + ports_on_net = [] + for port in ports_list: + new_port = cutil.make_port_dict(port[const.UUID], + port[const.PORTSTATE], + port[const.NETWORKID], + port[const.INTERFACEID]) + ports_on_net.append(new_port) + return ports_on_net def create_port(self, tenant_id, net_id, port_state, port_id, **kwargs): @@ -222,7 +250,7 @@ class UCSVICPlugin(L2DevicePluginBase): old_vlan_name = port_profile[const.PROFILE_VLAN_NAME] new_vlan_name = self._get_vlan_name_for_network(tenant_id, net_id) new_vlan_id = self._get_vlan_id_for_network(tenant_id, net_id) - self._client.change_vlan_in_profile(profile_name, old_vlan_name, + self._driver.change_vlan_in_profile(profile_name, old_vlan_name, new_vlan_name, self._ucsm_ip, self._ucsm_username, self._ucsm_password) @@ -242,7 +270,7 @@ class UCSVICPlugin(L2DevicePluginBase): profile_name = port_profile[const.PROFILE_NAME] old_vlan_name = port_profile[const.PROFILE_VLAN_NAME] new_vlan_name = conf.DEFAULT_VLAN_NAME - self._client.change_vlan_in_profile(profile_name, old_vlan_name, + self._driver.change_vlan_in_profile(profile_name, old_vlan_name, new_vlan_name, self._ucsm_ip, self._ucsm_username, self._ucsm_password) @@ -304,7 +332,7 @@ class UCSVICPlugin(L2DevicePluginBase): if self._port_profile_counter >= int(conf.MAX_UCSM_PORT_PROFILES): raise cexc.UCSMPortProfileLimit(net_id=net_id, port_id=port_id) profile_name = self._get_profile_name(port_id) - self._client.create_profile(profile_name, vlan_name, self._ucsm_ip, + self._driver.create_profile(profile_name, vlan_name, self._ucsm_ip, self._ucsm_username, self._ucsm_password) self._port_profile_counter += 1 new_port_profile = {const.PROFILE_NAME: profile_name, @@ -314,7 +342,7 @@ class UCSVICPlugin(L2DevicePluginBase): def _delete_port_profile(self, port_id, profile_name): """Delete port profile in UCSM""" - self._client.delete_profile(profile_name, self._ucsm_ip, + self._driver.delete_profile(profile_name, self._ucsm_ip, self._ucsm_username, self._ucsm_password) self._port_profile_counter -= 1 From c40afe46835f30e738112cd398ef0bc9379de25c Mon Sep 17 00:00:00 2001 From: Sumit Naiksatam Date: Sat, 20 Aug 2011 16:30:13 -0700 Subject: [PATCH 09/39] UCS plugin persistence. --- .../plugins/cisco/common/cisco_constants.py | 2 + quantum/plugins/cisco/ucs/cisco_ucs_plugin.py | 133 +++++------------- 2 files changed, 40 insertions(+), 95 deletions(-) diff --git a/quantum/plugins/cisco/common/cisco_constants.py b/quantum/plugins/cisco/common/cisco_constants.py index 197d3f0080..f3e3249c19 100644 --- a/quantum/plugins/cisco/common/cisco_constants.py +++ b/quantum/plugins/cisco/common/cisco_constants.py @@ -39,6 +39,8 @@ PPQOS = 'qos' PPID = 'portprofile_id' PPDEFAULT = 'default' VLANID = 'vlan_id' +VLANNAME = 'vlan_name' +PORTPROFILENAME = 'portprofile_name' ATTACHMENT = 'attachment' PORT_ID = 'port-id' diff --git a/quantum/plugins/cisco/ucs/cisco_ucs_plugin.py b/quantum/plugins/cisco/ucs/cisco_ucs_plugin.py index 7545ef898c..2ebea71cdd 100644 --- a/quantum/plugins/cisco/ucs/cisco_ucs_plugin.py +++ b/quantum/plugins/cisco/ucs/cisco_ucs_plugin.py @@ -29,6 +29,7 @@ from quantum.plugins.cisco.common import cisco_exceptions as cexc 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 +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 @@ -38,7 +39,6 @@ LOG.getLogger(const.LOGGER_COMPONENT_NAME) class UCSVICPlugin(L2DevicePluginBase): """UCS Device Plugin""" - _networks = {} def __init__(self): self._driver = utils.import_object(conf.UCSM_DRIVER) @@ -143,11 +143,8 @@ class UCSVICPlugin(L2DevicePluginBase): ports_list = network[const.NETWORKPORTS] ports_on_net = [] for port in ports_list: - new_port = cutil.make_port_dict(port[const.UUID], - port[const.PORTSTATE], - port[const.NETWORKID], - port[const.INTERFACEID]) - ports_on_net.append(new_port) + port_binding = udb.get_portbinding(port[const.UUID]) + ports_on_net.append(port_binding) return ports_on_net @@ -157,28 +154,28 @@ class UCSVICPlugin(L2DevicePluginBase): """ LOG.debug("UCSVICPlugin:create_port() 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] - net = self._get_network(tenant_id, net_id) - ports = net[const.NET_PORTS] 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] - new_port_dict = {const.PORT_ID: port_id, - const.PORT_STATE: const.PORT_UP, - const.ATTACHMENT: None, - const.PORT_PROFILE: new_port_profile} - ports[port_id] = new_port_dict - ucs_inventory.reserve_blade_interface(self._ucsm_ip, chassis_id, - blade_id, blade_data_dict, - tenant_id, port_id, - profile_name) - return new_port_dict + 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.add_portbinding(port_id, + rsvd_nic_dict[const.BLADE_INTF_DN], + profile_name, + conf.DEFAULT_VLAN_NAME, + conf.DEFAULT_VLAN_ID, qos) + return port_binding def delete_port(self, tenant_id, net_id, port_id, **kwargs): """ @@ -193,22 +190,12 @@ class UCSVICPlugin(L2DevicePluginBase): chassis_id = kwargs[const.CHASSIS_ID] blade_id = kwargs[const.BLADE_ID] interface_dn = kwargs[const.BLADE_INTF_DN] - port = self._get_port(tenant_id, net_id, port_id) - if port[const.ATTACHMENT]: - raise exc.PortInUse(net_id=net_id, port_id=port_id, - att_id=port[const.ATTACHMENT]) - try: - #TODO (Sumit): Before deleting port profile make sure that there - # is no VM using this port profile - port_profile = port[const.PORT_PROFILE] - self._delete_port_profile(port_id, - port_profile[const.PROFILE_NAME]) - net = self._get_network(tenant_id, net_id) - net[const.NET_PORTS].pop(port_id) - ucs_inventory.unreserve_blade_interface(self._ucsm_ip, chassis_id, - blade_id, interface_dn) - except KeyError: - raise exc.PortNotFound(net_id=net_id, port_id=port_id) + port_binding = udb.get_portbinding(port_id) + profile_name = port_binding[const.PORTPROFILENAME] + self._delete_port_profile(port_id, profile_name) + ucs_inventory.unreserve_blade_interface(self._ucsm_ip, chassis_id, + blade_id, interface_dn) + return udb.remove_portbinding(port_id) def update_port(self, tenant_id, net_id, port_id, port_state, **kwargs): """ @@ -216,10 +203,7 @@ class UCSVICPlugin(L2DevicePluginBase): """ LOG.debug("UCSVICPlugin:update_port() called\n") self._set_ucsm(kwargs[const.DEVICE_IP]) - port = self._get_port(tenant_id, net_id, port_id) - self._validate_port_state(port_state) - port[const.PORT_STATE] = port_state - return port + pass def get_port_details(self, tenant_id, net_id, port_id, **kwargs): """ @@ -228,7 +212,8 @@ class UCSVICPlugin(L2DevicePluginBase): """ LOG.debug("UCSVICPlugin:get_port_details() called\n") self._set_ucsm(kwargs[const.DEVICE_IP]) - return self._get_port(tenant_id, net_id, port_id) + port_binding = udb.get_portbinding(port_id) + return port_binding def plug_interface(self, tenant_id, net_id, port_id, remote_interface_id, **kwargs): @@ -238,24 +223,17 @@ class UCSVICPlugin(L2DevicePluginBase): """ LOG.debug("UCSVICPlugin:plug_interface() called\n") self._set_ucsm(kwargs[const.DEVICE_IP]) - self._validate_attachment(tenant_id, net_id, port_id, - remote_interface_id) - port = self._get_port(tenant_id, net_id, port_id) - if port[const.ATTACHMENT]: - raise exc.PortInUse(net_id=net_id, port_id=port_id, - att_id=port[const.ATTACHMENT]) - port[const.ATTACHMENT] = remote_interface_id - port_profile = port[const.PORT_PROFILE] - profile_name = port_profile[const.PROFILE_NAME] - old_vlan_name = port_profile[const.PROFILE_VLAN_NAME] + port_binding = udb.get_portbinding(port_id) + profile_name = port_binding[const.PORTPROFILENAME] + old_vlan_name = port_binding[const.VLANNAME] new_vlan_name = self._get_vlan_name_for_network(tenant_id, net_id) new_vlan_id = self._get_vlan_id_for_network(tenant_id, net_id) self._driver.change_vlan_in_profile(profile_name, old_vlan_name, new_vlan_name, self._ucsm_ip, self._ucsm_username, self._ucsm_password) - port_profile[const.PROFILE_VLAN_NAME] = new_vlan_name - port_profile[const.PROFILE_VLAN_ID] = new_vlan_id + return udb.update_portbinding(port_id, vlan_name=new_vlan_name, + vlan_id=new_vlan_id) def unplug_interface(self, tenant_id, net_id, port_id, **kwargs): """ @@ -264,18 +242,16 @@ class UCSVICPlugin(L2DevicePluginBase): """ LOG.debug("UCSVICPlugin:unplug_interface() called\n") self._set_ucsm(kwargs[const.DEVICE_IP]) - port = self._get_port(tenant_id, net_id, port_id) - port[const.ATTACHMENT] = None - port_profile = port[const.PORT_PROFILE] - profile_name = port_profile[const.PROFILE_NAME] - old_vlan_name = port_profile[const.PROFILE_VLAN_NAME] + port_binding = udb.get_portbinding(port_id) + profile_name = port_binding[const.PORTPROFILENAME] + old_vlan_name = port_binding[const.VLANNAME] new_vlan_name = conf.DEFAULT_VLAN_NAME self._driver.change_vlan_in_profile(profile_name, old_vlan_name, new_vlan_name, self._ucsm_ip, self._ucsm_username, self._ucsm_password) - port_profile[const.PROFILE_VLAN_NAME] = conf.DEFAULT_VLAN_NAME - port_profile[const.PROFILE_VLAN_ID] = conf.DEFAULT_VLAN_ID + return udb.update_portbinding(port_id, vlan_name=new_vlan_name, + vlan_id=conf.DEFAULT_VLAN_ID) def _get_profile_name(self, port_id): """Returns the port profile name based on the port UUID""" @@ -283,48 +259,15 @@ class UCSVICPlugin(L2DevicePluginBase): + cutil.get16ByteUUID(port_id) return profile_name - def _validate_port_state(self, port_state): - """Check the port state""" - if port_state.upper() not in (const.PORT_UP, const.PORT_DOWN): - raise exc.StateInvalid(port_state=port_state) - return True - - def _validate_attachment(self, tenant_id, network_id, port_id, - remote_interface_id): - """Check if the VIF can be attached""" - network = self._get_network(tenant_id, network_id) - for port in network[const.NET_PORTS].values(): - if port[const.ATTACHMENT] == remote_interface_id: - raise exc.PortInUse(net_id=network_id, - port_id=port_id, - att_id=port[const.ATTACHMENT]) - - def _get_network(self, tenant_id, network_id): - """Get the network object ref""" - network = self._networks.get(network_id) - if not network: - raise exc.NetworkNotFound(net_id=network_id) - return network - def _get_vlan_name_for_network(self, tenant_id, network_id): """Return the VLAN name as set by the L2 network plugin""" - net = self._get_network(tenant_id, network_id) - vlan_name = net[const.NET_VLAN_NAME] - return vlan_name + vlan_binding = cdb.get_vlan_binding(network_id) + return vlan_binding[const.VLANNAME] def _get_vlan_id_for_network(self, tenant_id, network_id): """Return the VLAN id as set by the L2 network plugin""" - net = self._get_network(tenant_id, network_id) - vlan_id = net[const.NET_VLAN_ID] - return vlan_id - - def _get_port(self, tenant_id, network_id, port_id): - """Get the port object ref""" - net = self._get_network(tenant_id, network_id) - port = net[const.NET_PORTS].get(port_id) - if not port: - raise exc.PortNotFound(net_id=network_id, port_id=port_id) - return port + vlan_binding = cdb.get_vlan_binding(network_id) + return vlan_binding[const.VLANID] def _create_port_profile(self, tenant_id, net_id, port_id, vlan_name, vlan_id): From a570af2974bb4908266ce73eef60dc780519f6fd Mon Sep 17 00:00:00 2001 From: rohitagarwalla Date: Sat, 20 Aug 2011 17:02:47 -0700 Subject: [PATCH 10/39] added new columns to models for ucs plugin multi blade support updated methods in ucs_db for newly added columns changed column dynamic_vnic_id in port binding table to blade_intf_dn updated tests to handle new column name --- quantum/plugins/cisco/db/ucs_db.py | 37 +++++++++++++++---- quantum/plugins/cisco/db/ucs_models.py | 19 +++++++--- .../plugins/cisco/tests/unit/test_database.py | 16 ++++---- 3 files changed, 51 insertions(+), 21 deletions(-) diff --git a/quantum/plugins/cisco/db/ucs_db.py b/quantum/plugins/cisco/db/ucs_db.py index 4cb96b2d24..2f54027950 100644 --- a/quantum/plugins/cisco/db/ucs_db.py +++ b/quantum/plugins/cisco/db/ucs_db.py @@ -155,7 +155,10 @@ def remove_dynamicvnic(vnic_id): def update_dynamicvnic(vnic_id, new_device_name=None, new_blade_id=None, - vnic_state=None): + vnic_state=None, blade_intf_dn=None, + blade_intf_order=None, blade_int_link_state=None, + blade_intf_oper_state=None, blade_intf_inst_type=None, + blade_intf_reservation=None): """Updates dynamic vnic""" LOG.debug("update_dynamicvnic() called") session = db.get_session() @@ -169,6 +172,18 @@ def update_dynamicvnic(vnic_id, new_device_name=None, new_blade_id=None, vnic.blade_id = new_blade_id if vnic_state: vnic.vnic_state = vnic_state + if blade_intf_dn: + vnic.blade_intf_dn = blade_intf_dn + if blade_intf_order: + vnic.blade_intf_order = blade_intf_order + if blade_int_link_state: + vnic.blade_int_link_state = blade_int_link_state + if blade_intf_oper_state: + vnic.blade_intf_oper_state = blade_intf_oper_state + if blade_intf_inst_type: + vnic.blade_intf_inst_type = blade_intf_inst_type + if blade_intf_reservation: + vnic.blade_intf_reservation = blade_intf_reservation session.merge(vnic) session.flush() return vnic @@ -291,7 +306,7 @@ def get_portbinding(port_id): raise c_exc.PortVnicNotFound(port_id=port_id) -def add_portbinding(port_id, dynamic_vnic_id, portprofile_name, +def add_portbinding(port_id, blade_intf_dn, portprofile_name, vlan_name, vlan_id, qos): """Adds a port binding""" LOG.debug("add_portbinding() called") @@ -302,7 +317,7 @@ def add_portbinding(port_id, dynamic_vnic_id, portprofile_name, one() raise c_exc.PortVnicBindingAlreadyExists(port_id=port_id) except exc.NoResultFound: - port_binding = ucs_models.PortBinding(port_id, dynamic_vnic_id, \ + port_binding = ucs_models.PortBinding(port_id, blade_intf_dn, \ portprofile_name, vlan_name, vlan_id, qos) session.add(port_binding) session.flush() @@ -324,8 +339,10 @@ def remove_portbinding(port_id): pass -def update_portbinding(port_id, dynamic_vnic_id=None, portprofile_name=None, - vlan_name=None, vlan_id=None, qos=None): +def update_portbinding(port_id, blade_intf_dn=None, portprofile_name=None, + vlan_name=None, vlan_id=None, qos=None, + tenant_id=None, instance_id=None, + vif_id=None): """Updates port binding""" LOG.debug("db update_portbinding() called") session = db.get_session() @@ -333,8 +350,8 @@ def update_portbinding(port_id, dynamic_vnic_id=None, portprofile_name=None, port_binding = session.query(ucs_models.PortBinding).\ filter_by(port_id=port_id).\ one() - if dynamic_vnic_id: - port_binding.dynamic_vnic_id = dynamic_vnic_id + if blade_intf_dn: + port_binding.blade_intf_dn = blade_intf_dn if portprofile_name: port_binding.portprofile_name = portprofile_name if vlan_name: @@ -343,6 +360,12 @@ def update_portbinding(port_id, dynamic_vnic_id=None, portprofile_name=None, port_binding.vlan_id = vlan_id if qos: port_binding.qos = qos + if tenant_id: + port_binding.tenant_id = tenant_id + if instance_id: + port_binding.instance_id = instance_id + if vif_id: + port_binding.vif_id = vif_id session.merge(port_binding) session.flush() return port_binding diff --git a/quantum/plugins/cisco/db/ucs_models.py b/quantum/plugins/cisco/db/ucs_models.py index a146ac828a..be7c18aab9 100644 --- a/quantum/plugins/cisco/db/ucs_models.py +++ b/quantum/plugins/cisco/db/ucs_models.py @@ -53,6 +53,12 @@ class DynamicVnic(BASE, L2NetworkBase): blade_id = Column(String(255), ForeignKey("ucs_blades.uuid"), nullable=False) vnic_state = Column(String(255)) + blade_intf_dn = Column(String(255)) + blade_intf_order = Column(String(255)) + blade_int_link_state = Column(String(255)) + blade_intf_oper_state = Column(String(255)) + blade_intf_inst_type = Column(String(255)) + blade_intf_reservation = Column(String(255)) def __init__(self, device_name, blade_id, vnic_state): self.uuid = uuid.uuid4() @@ -105,19 +111,20 @@ class PortBinding(BASE, L2NetworkBase): id = Column(Integer, primary_key=True, autoincrement=True) port_id = Column(String(255), ForeignKey("ports.uuid"), nullable=False) - dynamic_vnic_id = Column(String(255), ForeignKey("dynamic_vnics.uuid"), - nullable=False) + blade_intf_dn = Column(String(255), nullable=False) portprofile_name = Column(String(255)) vlan_name = Column(String(255)) vlan_id = Column(Integer) qos = Column(String(255)) + tenant_id = Column(String(255)) + instance_id = Column(String(255)) + vif_id = Column(String(255)) ports = relation(models.Port, uselist=False) - dynamic_vnics = relation(DynamicVnic, uselist=False) - def __init__(self, port_id, dynamic_vnic_id, portprofile_name, + def __init__(self, port_id, blade_intf_dn, portprofile_name, vlan_name, vlan_id, qos): self.port_id = port_id - self.dynamic_vnic_id = dynamic_vnic_id + self.blade_intf_dn = blade_intf_dn self.portprofile_name = portprofile_name self.vlan_name = vlan_name self.vlan_id = vlan_id @@ -125,5 +132,5 @@ class PortBinding(BASE, L2NetworkBase): def __repr__(self): return "" % \ - (self.port_id, self.dynamic_vnic_id, self.portprofile_name, + (self.port_id, self.blade_intf_dn, self.portprofile_name, self.vlan_name, self.vlan_id, self.qos) diff --git a/quantum/plugins/cisco/tests/unit/test_database.py b/quantum/plugins/cisco/tests/unit/test_database.py index d97592b560..8e3b7b6b8c 100644 --- a/quantum/plugins/cisco/tests/unit/test_database.py +++ b/quantum/plugins/cisco/tests/unit/test_database.py @@ -272,7 +272,7 @@ class UcsDB(object): LOG.debug("Getting port binding for port: %s" % bind.port_id) port_bind_dict = {} port_bind_dict["port-id"] = bind.port_id - port_bind_dict["dynamic-vnic-id"] = str(bind.dynamic_vnic_id) + port_bind_dict["blade-intf-dn"] = str(bind.blade_intf_dn) port_bind_dict["portprofile-name"] = bind.portprofile_name port_bind_dict["vlan-name"] = bind.vlan_name port_bind_dict["vlan-id"] = str(bind.vlan_id) @@ -290,7 +290,7 @@ class UcsDB(object): LOG.debug("Getting port binding for port: %s" % bind.port_id) port_bind_dict = {} port_bind_dict["port-id"] = bind.port_id - port_bind_dict["dynamic-vnic-id"] = str(bind.dynamic_vnic_id) + port_bind_dict["blade-intf-dn"] = str(bind.blade_intf_dn) port_bind_dict["portprofile-name"] = bind.portprofile_name port_bind_dict["vlan-name"] = bind.vlan_name port_bind_dict["vlan-id"] = str(bind.vlan_id) @@ -300,16 +300,16 @@ class UcsDB(object): LOG.error("Failed to get port binding: %s" % str(exc)) return port_binding - def create_port_binding(self, port_id, dynamic_vnic_id, portprofile_name, \ + def create_port_binding(self, port_id, blade_intf_dn, portprofile_name, \ vlan_name, vlan_id, qos): """create port binding""" port_bind_dict = {} try: - res = ucs_db.add_portbinding(port_id, dynamic_vnic_id, \ + res = ucs_db.add_portbinding(port_id, blade_intf_dn, \ portprofile_name, vlan_name, vlan_id, qos) LOG.debug("Created port binding: %s" % res.port_id) port_bind_dict["port-id"] = res.port_id - port_bind_dict["dynamic-vnic-id"] = str(res.dynamic_vnic_id) + port_bind_dict["blade-intf-dn"] = str(res.blade_intf_dn) port_bind_dict["portprofile-name"] = res.portprofile_name port_bind_dict["vlan-name"] = res.vlan_name port_bind_dict["vlan-id"] = str(res.vlan_id) @@ -329,16 +329,16 @@ class UcsDB(object): except Exception, exc: raise Exception("Failed to delete port profile: %s" % str(exc)) - def update_port_binding(self, port_id, dynamic_vnic_id, \ + def update_port_binding(self, port_id, blade_intf_dn, \ portprofile_name, vlan_name, vlan_id, qos): """update port binding""" try: - res = ucs_db.update_portbinding(port_id, dynamic_vnic_id, \ + res = ucs_db.update_portbinding(port_id, blade_intf_dn, \ portprofile_name, vlan_name, vlan_id, qos) LOG.debug("Updating port binding: %s" % res.port_id) port_bind_dict = {} port_bind_dict["port-id"] = res.port_id - port_bind_dict["dynamic-vnic-id"] = str(res.dynamic_vnic_id) + port_bind_dict["dynamic-vnic-id"] = str(res.blade_intf_dn) port_bind_dict["portprofile-name"] = res.portprofile_name port_bind_dict["vlan-name"] = res.vlan_name port_bind_dict["vlan-id"] = str(res.vlan_id) From 6b78dfc0b865aa76d361fc219fd601948aee6660 Mon Sep 17 00:00:00 2001 From: Sumit Naiksatam Date: Sat, 20 Aug 2011 18:20:43 -0700 Subject: [PATCH 11/39] UCS persistence fixes. --- quantum/plugins/cisco/l2network_plugin.py | 84 +++++++------------ quantum/plugins/cisco/ucs/cisco_ucs_plugin.py | 4 +- 2 files changed, 32 insertions(+), 56 deletions(-) diff --git a/quantum/plugins/cisco/l2network_plugin.py b/quantum/plugins/cisco/l2network_plugin.py index 94aa07ab27..225468bd8e 100644 --- a/quantum/plugins/cisco/l2network_plugin.py +++ b/quantum/plugins/cisco/l2network_plugin.py @@ -30,8 +30,10 @@ 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 from quantum.plugins.cisco.common import cisco_credentials as cred +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 +from quantum.plugins.cisco.db import ucs_db as udb LOG.basicConfig(level=LOG.WARN) LOG.getLogger(const.LOGGER_COMPONENT_NAME) @@ -66,7 +68,7 @@ class L2Network(QuantumPluginBase): networks_list = db.network_list(tenant_id) new_networks_list = [] for network in networks_list: - new_network_dict = self._make_net_dict(network[const.UUID], + new_network_dict = cutil.make_net_dict(network[const.UUID], network[const.NETWORKNAME], []) new_networks_list.append(new_network_dict) @@ -109,7 +111,7 @@ class L2Network(QuantumPluginBase): self.delete_port(tenant_id, net_id, port[const.PORTID]) self._invoke_device_plugins(self._func_name(), [tenant_id, net_id]) - net_dict = self._make_net_dict(net[const.UUID], + net_dict = cutil.make_net_dict(net[const.UUID], net[const.NETWORKNAME], []) self._release_vlan_for_tenant(tenant_id, net_id) @@ -129,13 +131,13 @@ class L2Network(QuantumPluginBase): ports_list = network[const.NETWORKPORTS] ports_on_net = [] for port in ports_list: - new_port = self._make_port_dict(port[const.UUID], + new_port = cutil.make_port_dict(port[const.UUID], port[const.PORTSTATE], port[const.NETWORKID], port[const.INTERFACEID]) ports_on_net.append(new_port) - new_network = self._make_net_dict(network[const.UUID], + new_network = cutil.make_net_dict(network[const.UUID], network[const.NETWORKNAME], ports_on_net) @@ -147,11 +149,10 @@ class L2Network(QuantumPluginBase): Virtual Network. """ LOG.debug("rename_network() called\n") - network = db.network_get(net_id) + network = db.network_rename(tenant_id, net_id, new_name) self._invoke_device_plugins(self._func_name(), [tenant_id, net_id, new_name]) - network = db.network_rename(tenant_id, net_id, new_name) - net_dict = self._make_net_dict(network[const.UUID], + net_dict = cutil.make_net_dict(network[const.UUID], network[const.NETWORKNAME], []) return net_dict @@ -167,7 +168,7 @@ class L2Network(QuantumPluginBase): ports_list = network[const.NETWORKPORTS] ports_on_net = [] for port in ports_list: - new_port = self._make_port_dict(port[const.UUID], + new_port = cutil.make_port_dict(port[const.UUID], port[const.PORTSTATE], port[const.NETWORKID], port[const.INTERFACEID]) @@ -185,7 +186,7 @@ class L2Network(QuantumPluginBase): self._invoke_device_plugins(self._func_name(), [tenant_id, net_id, port_state, unique_port_id_string]) - new_port_dict = self._make_port_dict(port[const.UUID], + new_port_dict = cutil.make_port_dict(port[const.UUID], port[const.PORTSTATE], port[const.NETWORKID], port[const.INTERFACEID]) @@ -200,11 +201,18 @@ class L2Network(QuantumPluginBase): """ LOG.debug("delete_port() called\n") network = db.network_get(net_id) - self._invoke_device_plugins(self._func_name(), [tenant_id, net_id, - port_id]) - db.port_destroy(net_id, port_id) - new_port_dict = self._make_port_dict(port_id, None, None, None) - return new_port_dict + port = db.port_get(net_id, port_id) + attachment_id = port[const.INTERFACEID] + if not attachment_id: + self._invoke_device_plugins(self._func_name(), [tenant_id, + net_id, + port_id]) + db.port_destroy(net_id, port_id) + new_port_dict = cutil.make_port_dict(port_id, None, None, None) + return new_port_dict + else: + raise exc.PortInUse(port_id=port_id, net_id=net_id, + att_id=attachment_id) def update_port(self, tenant_id, net_id, port_id, port_state): """ @@ -216,7 +224,7 @@ class L2Network(QuantumPluginBase): port_id, port_state]) self._validate_port_state(port_state) db.port_set_state(net_id, port_id, port_state) - new_port_dict = self._make_port_dict(port_id, port_state, net_id, + new_port_dict = cutil.make_port_dict(port_id, port_state, net_id, None) return new_port_dict @@ -230,7 +238,7 @@ class L2Network(QuantumPluginBase): self._invoke_device_plugins(self._func_name(), [tenant_id, net_id, port_id]) port = db.port_get(net_id, port_id) - new_port_dict = self._make_port_dict(port[const.UUID], + new_port_dict = cutil.make_port_dict(port[const.UUID], port[const.PORTSTATE], port[const.NETWORKID], port[const.INTERFACEID]) @@ -269,7 +277,7 @@ class L2Network(QuantumPluginBase): pplist = cdb.get_all_portprofiles() new_pplist = [] for portprofile in pplist: - new_pp = self._make_portprofile_dict(tenant_id, + new_pp = cutil.make_portprofile_dict(tenant_id, portprofile[const.UUID], portprofile[const.PPNAME], portprofile[const.PPQOS]) @@ -286,7 +294,7 @@ class L2Network(QuantumPluginBase): raise cexc.PortProfileNotFound(tenant_id=tenant_id, portprofile_id=profile_id) - new_pp = self._make_portprofile_dict(tenant_id, + new_pp = cutil.make_portprofile_dict(tenant_id, portprofile[const.UUID], portprofile[const.PPNAME], portprofile[const.PPQOS]) @@ -297,7 +305,7 @@ class L2Network(QuantumPluginBase): LOG.debug("create_portprofile() called\n") portprofile = cdb.add_portprofile(tenant_id, profile_name, const.NO_VLAN_ID, qos) - new_pp = self._make_portprofile_dict(tenant_id, + new_pp = cutil.make_portprofile_dict(tenant_id, portprofile[const.UUID], portprofile[const.PPNAME], portprofile[const.PPQOS]) @@ -328,7 +336,7 @@ class L2Network(QuantumPluginBase): raise cexc.PortProfileNotFound(tenant_id=tenant_id, portprofile_id=profile_id) portprofile = cdb.update_portprofile(tenant_id, profile_id, new_name) - new_pp = self._make_portprofile_dict(tenant_id, + new_pp = cutil.make_portprofile_dict(tenant_id, portprofile[const.UUID], portprofile[const.PPNAME], portprofile[const.PPQOS]) @@ -364,7 +372,7 @@ class L2Network(QuantumPluginBase): LOG.debug("create_default_portprofile() called\n") portprofile = cdb.add_portprofile(tenant_id, profile_name, const.NO_VLAN_ID, qos) - new_pp = self._make_portprofile_dict(tenant_id, + new_pp = cutil.make_portprofile_dict(tenant_id, portprofile[const.UUID], portprofile[const.PPNAME], portprofile[const.PPQOS]) @@ -526,40 +534,6 @@ class L2Network(QuantumPluginBase): """Getting the name of the calling funciton""" return inspect.stack()[1 + offset][3] - def _make_net_dict(self, net_id, net_name, ports): - """Helper funciton""" - res = {const.NET_ID: net_id, const.NET_NAME: net_name} - res[const.NET_PORTS] = ports - return res - - def _make_port_dict(self, port_id, port_state, net_id, attachment): - """Helper funciton""" - res = {const.PORT_ID: port_id, const.PORT_STATE: port_state} - res[const.NET_ID] = net_id - res[const.ATTACHMENT] = attachment - return res - - def _make_portprofile_dict(self, tenant_id, profile_id, profile_name, - qos): - """Helper funciton""" - profile_associations = self._make_portprofile_assc_list(tenant_id, - profile_id) - res = {const.PROFILE_ID: str(profile_id), - const.PROFILE_NAME: profile_name, - const.PROFILE_ASSOCIATIONS: profile_associations, - const.PROFILE_VLAN_ID: None, - const.PROFILE_QOS: qos} - return res - - def _make_portprofile_assc_list(self, tenant_id, profile_id): - """Helper function to create port profile association list""" - plist = cdb.get_pp_binding(tenant_id, profile_id) - assc_list = [] - for port in plist: - assc_list.append(port[const.PORTID]) - - return assc_list - def _get_qos_level(self, tenant_id, qos_id): """Return a QoS level based on the ID""" qos_level = self._qos_levels.get(qos_id) diff --git a/quantum/plugins/cisco/ucs/cisco_ucs_plugin.py b/quantum/plugins/cisco/ucs/cisco_ucs_plugin.py index 2ebea71cdd..023e4347fb 100644 --- a/quantum/plugins/cisco/ucs/cisco_ucs_plugin.py +++ b/quantum/plugins/cisco/ucs/cisco_ucs_plugin.py @@ -89,7 +89,9 @@ class UCSVICPlugin(L2DevicePluginBase): LOG.debug("UCSVICPlugin:delete_network() called\n") self._set_ucsm(kwargs[const.DEVICE_IP]) net = db.network_get(net_id) - self._driver.delete_vlan(net[const.NET_VLAN_NAME], self._ucsm_ip, + vlan_binding = cdb.get_vlan_binding(net[const.UUID]) + vlan_name = vlan_binding[const.VLANNAME] + self._driver.delete_vlan(vlan_name, self._ucsm_ip, self._ucsm_username, self._ucsm_password) net_dict = cutil.make_net_dict(net[const.UUID], net[const.NETWORKNAME], From 825f6c5c5ede31d97d9892e188312ffe3e531720 Mon Sep 17 00:00:00 2001 From: Sumit Naiksatam Date: Sat, 20 Aug 2011 20:37:51 -0700 Subject: [PATCH 12/39] UCS inventore persistence and pep8/pylint fixes. --- .../cisco/tests/unit/test_cisco_extension.py | 12 ++---- .../plugins/cisco/ucs/cisco_ucs_inventory.py | 43 +++++++++++++++---- quantum/plugins/cisco/ucs/cisco_ucs_plugin.py | 10 ++--- 3 files changed, 43 insertions(+), 22 deletions(-) diff --git a/quantum/plugins/cisco/tests/unit/test_cisco_extension.py b/quantum/plugins/cisco/tests/unit/test_cisco_extension.py index 36e8d52342..f69ac3df0c 100644 --- a/quantum/plugins/cisco/tests/unit/test_cisco_extension.py +++ b/quantum/plugins/cisco/tests/unit/test_cisco_extension.py @@ -640,8 +640,7 @@ class CredentialExtensionTest(unittest.TestCase): self.test_credential_data = {'credential': {'credential_name': 'cred8', 'user_name': 'newUser2', - 'password': 'newPasswd1' - }} + 'password': 'newPasswd1'}} def test_list_credentials(self): #Create Credential before listing @@ -653,8 +652,7 @@ class CredentialExtensionTest(unittest.TestCase): req_body2 = json.dumps({'credential': {'credential_name': 'cred9', 'user_name': 'newUser2', - 'password': 'newPasswd2' - }}) + 'password': 'newPasswd2'}}) create_response2 = self.test_app.post( self.credential_path, req_body2, content_type=self.contenttype) @@ -735,8 +733,7 @@ class CredentialExtensionTest(unittest.TestCase): rename_req_body = json.dumps({'credential': {'credential_name': 'cred3', 'user_name': 'RenamedUser', - 'password': 'Renamedpassword' - }}) + 'password': 'Renamedpassword'}}) rename_path_temp = self.cred_second_path +\ resp_body['credentials']['credential']['id'] rename_path = str(rename_path_temp) @@ -767,8 +764,7 @@ class CredentialExtensionTest(unittest.TestCase): rename_req_body = json.dumps({'credential': {'credential_name': 'cred3', 'user_name': 'RenamedUser', - 'password': 'Renamedpassword' - }}) + 'password': 'Renamedpassword'}}) rename_path_temp = self.cred_second_path + credential_id rename_path = str(rename_path_temp) rename_response = self.test_app.put(rename_path, rename_req_body, diff --git a/quantum/plugins/cisco/ucs/cisco_ucs_inventory.py b/quantum/plugins/cisco/ucs/cisco_ucs_inventory.py index ae9aa49708..f2dd3553e3 100644 --- a/quantum/plugins/cisco/ucs/cisco_ucs_inventory.py +++ b/quantum/plugins/cisco/ucs/cisco_ucs_inventory.py @@ -26,6 +26,7 @@ from quantum.plugins.cisco.common import cisco_constants as const from quantum.plugins.cisco.common import cisco_credentials as cred from quantum.plugins.cisco.common import cisco_exceptions as cexc from quantum.plugins.cisco.common import cisco_utils as cutil +from quantum.plugins.cisco.db import ucs_db as udb from quantum.plugins.cisco.ucs \ import cisco_ucs_inventory_configuration as conf from quantum.plugins.cisco.ucs import cisco_ucs_network_driver @@ -115,7 +116,7 @@ class UCSInventory(object): blade_list.append(blade_id) chassis_dict[chassis_id] = blade_list self._inventory[ucsm_ip] = chassis_dict - + self.build_inventory_state() def _get_host_name(self, ucsm_ip, chassis_id, blade_id): @@ -132,6 +133,7 @@ class UCSInventory(object): unreserved_counter = 0 for blade_intf in blade_intf_data.keys(): + dist_name = blade_intf_data[blade_intf][const.BLADE_INTF_DN] if (blade_intf_data[blade_intf][const.BLADE_INTF_LINK_STATE] == \ const.BLADE_INTF_STATE_UNALLOCATED or \ blade_intf_data[blade_intf][const.BLADE_INTF_LINK_STATE] == \ @@ -141,14 +143,25 @@ class UCSInventory(object): blade_intf_data[blade_intf][const.BLADE_INTF_RESERVATION] = \ const.BLADE_INTF_UNRESERVED unreserved_counter += 1 + blade_intf_data[blade_intf][const.TENANTID] = None + blade_intf_data[blade_intf][const.PORTID] = None + blade_intf_data[blade_intf][const.PROFILE_ID] = None + blade_intf_data[blade_intf][const.INSTANCE_ID] = None + blade_intf_data[blade_intf][const.VIF_ID] = None else: blade_intf_data[blade_intf][const.BLADE_INTF_RESERVATION] = \ const.BLADE_INTF_RESERVED - blade_intf_data[blade_intf][const.TENANTID] = None - blade_intf_data[blade_intf][const.PORTID] = None - blade_intf_data[blade_intf][const.PROFILE_ID] = None - blade_intf_data[blade_intf][const.INSTANCE_ID] = None - blade_intf_data[blade_intf][const.VIF_ID] = None + port_binding = udb.get_portbinding_dn(dist_name) + blade_intf_data[blade_intf][const.TENANTID] = \ + port_binding[const.TENANTID] + blade_intf_data[blade_intf][const.PORTID] = \ + port_binding[const.PORTID] + blade_intf_data[blade_intf][const.PROFILE_ID] = \ + port_binding[const.PORTPROFILENAME] + blade_intf_data[blade_intf][const.INSTANCE_ID] = \ + port_binding[const.INSTANCE_ID] + blade_intf_data[blade_intf][const.VIF_ID] = \ + port_binding[const.VIF_ID] blade_data = {const.BLADE_INTF_DATA: blade_intf_data, const.BLADE_UNRESERVED_INTF_COUNT: unreserved_counter} @@ -287,8 +300,8 @@ class UCSInventory(object): const.BLADE_INTF_RESERVED blade_intf_data[blade_intf][const.TENANTID] = tenant_id blade_intf_data[blade_intf][const.PORTID] = port_id - blade_intf_data[blade_intf][const.PROFILE_ID] = \ - portprofile_name + #blade_intf_data[blade_intf][const.PROFILE_ID] = \ + # portprofile_name blade_intf_data[blade_intf][const.INSTANCE_ID] = None dev_eth_name = blade_intf_data[blade_intf] \ [const.BLADE_INTF_RHEL_DEVICE_NAME] @@ -304,6 +317,11 @@ class UCSInventory(object): reserved_nic_dict = {const.RESERVED_NIC_HOSTNAME: host_name, const.RESERVED_NIC_NAME: dev_eth_name, const.BLADE_INTF_DN: blade_intf} + port_binding = udb.add_portbinding(port_id, blade_intf, None, + None, None, None) + udb.update_portbinding(port_id, + tenant_id=blade_intf_data[blade_intf]\ + [const.TENANTID]) LOG.debug("Reserved blade interface: %s\n" % reserved_nic_dict) return reserved_nic_dict @@ -379,6 +397,10 @@ class UCSInventory(object): host_name = self._get_host_name(ucsm_ip, chassis_id, blade_id) + port_binding = udb.get_portbinding_dn(blade_intf) + port_id = port_binding[const.PORTID] + udb.update_portbinding(port_id, + instance_id=instance_id) return host_name return None @@ -402,7 +424,10 @@ class UCSInventory(object): [const.INSTANCE_ID] == instance_id: blade_intf_data[blade_intf][const.VIF_ID] = \ vif_id - + port_binding = udb.get_portbinding_dn(blade_intf) + port_id = port_binding[const.PORTID] + udb.update_portbinding(port_id, + vif_id=vif_id) return blade_intf_data[blade_intf]\ [const.BLADE_INTF_RHEL_DEVICE_NAME] return None diff --git a/quantum/plugins/cisco/ucs/cisco_ucs_plugin.py b/quantum/plugins/cisco/ucs/cisco_ucs_plugin.py index 023e4347fb..f3ecf72eff 100644 --- a/quantum/plugins/cisco/ucs/cisco_ucs_plugin.py +++ b/quantum/plugins/cisco/ucs/cisco_ucs_plugin.py @@ -172,11 +172,11 @@ class UCSVICPlugin(L2DevicePluginBase): blade_id, blade_data_dict, tenant_id, port_id, profile_name) - port_binding = udb.add_portbinding(port_id, - rsvd_nic_dict[const.BLADE_INTF_DN], - profile_name, - conf.DEFAULT_VLAN_NAME, - conf.DEFAULT_VLAN_ID, qos) + 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) return port_binding def delete_port(self, tenant_id, net_id, port_id, **kwargs): From beba040e88a6e15d6dba9c6bd38b46689ca5940d Mon Sep 17 00:00:00 2001 From: rohitagarwalla Date: Sat, 20 Aug 2011 20:51:07 -0700 Subject: [PATCH 13/39] adding helper function for port binding model --- quantum/plugins/cisco/db/ucs_db.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/quantum/plugins/cisco/db/ucs_db.py b/quantum/plugins/cisco/db/ucs_db.py index 2f54027950..5878641b58 100644 --- a/quantum/plugins/cisco/db/ucs_db.py +++ b/quantum/plugins/cisco/db/ucs_db.py @@ -371,3 +371,15 @@ def update_portbinding(port_id, blade_intf_dn=None, portprofile_name=None, 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") + session = db.get_session() + try: + port_binding = session.query(ucs_models.PortBinding).\ + filter_by(blade_intf_dn=blade_intf_dn).\ + one() + return port_binding + except exc.NoResultFound: + return [] From 2df72d910faed4bb92580c0a24cbd762c086e8a0 Mon Sep 17 00:00:00 2001 From: rohitagarwalla Date: Sat, 20 Aug 2011 20:58:13 -0700 Subject: [PATCH 14/39] fixing pep8 error --- quantum/plugins/cisco/db/ucs_db.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/quantum/plugins/cisco/db/ucs_db.py b/quantum/plugins/cisco/db/ucs_db.py index 5878641b58..49ff512efd 100644 --- a/quantum/plugins/cisco/db/ucs_db.py +++ b/quantum/plugins/cisco/db/ucs_db.py @@ -371,7 +371,8 @@ def update_portbinding(port_id, blade_intf_dn=None, portprofile_name=None, 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") From 3cf38401c4dec63f6bfe4188ac54627e9cb1a165 Mon Sep 17 00:00:00 2001 From: Sumit Naiksatam Date: Sat, 20 Aug 2011 22:10:33 -0700 Subject: [PATCH 15/39] Changes to support calls from VIF Driver and Scheduler. --- .../plugins/cisco/common/cisco_constants.py | 2 +- .../plugins/cisco/conf/l2network_plugin.ini | 2 +- .../cisco/models/l2network_multi_blade.py | 26 ++++++++- .../plugins/cisco/ucs/cisco_ucs_inventory.py | 58 ++----------------- 4 files changed, 31 insertions(+), 57 deletions(-) diff --git a/quantum/plugins/cisco/common/cisco_constants.py b/quantum/plugins/cisco/common/cisco_constants.py index 9182d58d50..f2fa8805f7 100644 --- a/quantum/plugins/cisco/common/cisco_constants.py +++ b/quantum/plugins/cisco/common/cisco_constants.py @@ -41,7 +41,7 @@ PPDEFAULT = 'default' VLANID = 'vlan_id' VLANNAME = 'vlan_name' PORTPROFILENAME = 'portprofile_name' -QOS='qos' +QOS = 'qos' ATTACHMENT = 'attachment' PORT_ID = 'port-id' diff --git a/quantum/plugins/cisco/conf/l2network_plugin.ini b/quantum/plugins/cisco/conf/l2network_plugin.ini index 494279e790..421d301acd 100644 --- a/quantum/plugins/cisco/conf/l2network_plugin.ini +++ b/quantum/plugins/cisco/conf/l2network_plugin.ini @@ -13,7 +13,7 @@ max_port_profiles=65568 max_networks=65568 [MODEL] -model_class=quantum.plugins.cisco.models.l2network_single_blade.L2NetworkSinlgeBlade +model_class=quantum.plugins.cisco.models.l2network_multi_blade.L2NetworkMultiBlade [SEGMENTATION] manager_class=quantum.plugins.cisco.segmentation.l2network_vlan_mgr.L2NetworkVLANMgr diff --git a/quantum/plugins/cisco/models/l2network_multi_blade.py b/quantum/plugins/cisco/models/l2network_multi_blade.py index a6c98cfac2..aea084781f 100644 --- a/quantum/plugins/cisco/models/l2network_multi_blade.py +++ b/quantum/plugins/cisco/models/l2network_multi_blade.py @@ -116,6 +116,8 @@ class L2NetworkMultiBlade(L2NetworkModelBase): def create_port(self, args): """Support for the Quantum core API call""" + if not const.UCS_PLUGIN in self._plugins.keys(): + return least_reserved_blade_dict = \ self._ucs_inventory.get_least_reserved_blade() if not least_reserved_blade_dict: @@ -129,6 +131,8 @@ class L2NetworkMultiBlade(L2NetworkModelBase): def delete_port(self, args): """Support for the Quantum core API call""" + if not const.UCS_PLUGIN in self._plugins.keys(): + return rsvd_info = \ self._ucs_inventory.get_rsvd_blade_intf_by_port(args[0], args[2]) @@ -152,6 +156,8 @@ class L2NetworkMultiBlade(L2NetworkModelBase): def plug_interface(self, args): """Support for the Quantum core API call""" + if not const.UCS_PLUGIN in self._plugins.keys(): + return rsvd_info = \ self._ucs_inventory.get_rsvd_blade_intf_by_port(args[0], args[2]) @@ -162,6 +168,8 @@ class L2NetworkMultiBlade(L2NetworkModelBase): def unplug_interface(self, args): """Support for the Quantum core API call""" + if not const.UCS_PLUGIN in self._plugins.keys(): + return rsvd_info = \ self._ucs_inventory.get_rsvd_blade_intf_by_port(args[0], args[2]) @@ -173,7 +181,12 @@ class L2NetworkMultiBlade(L2NetworkModelBase): def get_host(self, args): """Provides the hostname on which a dynamic vnic is reserved""" LOG.debug("get_host() called\n") - host_list = {const.HOST_LIST: {const.HOST_1: platform.node()}} + if not const.UCS_PLUGIN in self._plugins.keys(): + return + tenant_id = args[0] + instance_id = args[1] + host_name = self._ucs_inventory.get_host_name(tenant_id, instance_id) + host_list = {const.HOST_LIST: {const.HOST_1: host_name}} return host_list def get_instance_port(self, args): @@ -181,6 +194,13 @@ class L2NetworkMultiBlade(L2NetworkModelBase): Get the portprofile name and the device namei for the dynamic vnic """ LOG.debug("get_instance_port() called\n") - vif_desc = {const.VIF_DESC: - {const.DEVICENAME: "eth2", const.UCSPROFILE: "default"}} + if not const.UCS_PLUGIN in self._plugins.keys(): + return + tenant_id = args[0] + instance_id = args[1] + vif_id = args[2] + vif_info = self._ucs_inventory.get_instance_port(tenant_id, + instance_id, + vif_id) + vif_desc = {const.VIF_DESC: vif_info} return vif_desc diff --git a/quantum/plugins/cisco/ucs/cisco_ucs_inventory.py b/quantum/plugins/cisco/ucs/cisco_ucs_inventory.py index f2dd3553e3..c9a031d40e 100644 --- a/quantum/plugins/cisco/ucs/cisco_ucs_inventory.py +++ b/quantum/plugins/cisco/ucs/cisco_ucs_inventory.py @@ -404,7 +404,7 @@ class UCSInventory(object): return host_name return None - def get_instance_port(self, tenant_id, instance_id, vif_id): + def get_instance_port(self, tenant_id, instance_id, vif_id=None): """ Return the device name for a reserved interface """ @@ -428,60 +428,14 @@ class UCSInventory(object): port_id = port_binding[const.PORTID] udb.update_portbinding(port_id, vif_id=vif_id) - return blade_intf_data[blade_intf]\ + device_name = blade_intf_data[blade_intf]\ [const.BLADE_INTF_RHEL_DEVICE_NAME] + profile_name = port_binding[const.PORTPROFILENAME] + return {const.DEVICENAME: device_name, + const.UCSPROFILE: profile_name} return None def add_blade(self, ucsm_ip, chassis_id, blade_id): """Add a blade to the inventory""" + # TODO (Sumit) pass - - -def main(): - #client = UCSInventory() - #client.build_state() - ucsinv = UCSInventory() - reserved_nics = [] - ucsinv.build_inventory_state() - while True: - reserved_blade_dict = ucsinv.get_least_reserved_blade() - if not reserved_blade_dict: - print "No more unreserved blades\n" - break - - least_reserved_blade_ucsm = \ - reserved_blade_dict[const.LEAST_RSVD_BLADE_UCSM] - least_reserved_blade_chassis = \ - reserved_blade_dict[const.LEAST_RSVD_BLADE_CHASSIS] - least_reserved_blade_id = \ - reserved_blade_dict[const.LEAST_RSVD_BLADE_ID] - least_reserved_blade_data = \ - reserved_blade_dict[const.LEAST_RSVD_BLADE_DATA] - reserved_nic_dict = \ - ucsinv.reserve_blade_interface(least_reserved_blade_ucsm, - least_reserved_blade_chassis, - least_reserved_blade_id, - least_reserved_blade_data, - "demo", "12345", "profilename") - if reserved_nic_dict: - reserved_intf_nic_info = {const.RESERVED_INTERFACE_UCSM: - least_reserved_blade_ucsm, - const.RESERVED_INTERFACE_CHASSIS: - least_reserved_blade_chassis, - const.RESERVED_INTERFACE_BLADE: - least_reserved_blade_id, - const.RESERVED_INTERFACE_DN: - reserved_nic_dict[const.BLADE_INTF_DN]} - reserved_nics.append(reserved_intf_nic_info) - #break - - for rnic in reserved_nics: - ucsinv.unreserve_blade_interface( - rnic[const.RESERVED_INTERFACE_UCSM], - rnic[const.RESERVED_INTERFACE_CHASSIS], - rnic[const.RESERVED_INTERFACE_BLADE], - rnic[const.RESERVED_INTERFACE_DN]) - - -if __name__ == '__main__': - main() From 0cd69434071944b7b3b46d2d74481333c966e8e3 Mon Sep 17 00:00:00 2001 From: Sumit Naiksatam Date: Sat, 20 Aug 2011 22:31:50 -0700 Subject: [PATCH 16/39] Changes to reflect the new features (mutli-blade, multi-chassis support). --- quantum/plugins/cisco/README | 54 ++++++++++++++++++++++++++++++++---- 1 file changed, 49 insertions(+), 5 deletions(-) diff --git a/quantum/plugins/cisco/README b/quantum/plugins/cisco/README index e15c9ac389..095a69adc0 100755 --- a/quantum/plugins/cisco/README +++ b/quantum/plugins/cisco/README @@ -2,7 +2,8 @@ README: A Quantum Plugin Framework for Supporting L2 Networks Spannning Multiple Switches ========================================================================================= -:Author: Sumit Naiksatam, Ram Durairaj, Mark Voelker, Edgar Magana, Shweta Padubidri, Rohit Agarwalla, Ying Liu, Debo Dutta +:Author: Sumit Naiksatam, Ram Durairaj, Mark Voelker, Edgar Magana, Shweta Padubidri, + Rohit Agarwalla, Ying Liu, Debo Dutta :Contact: netstack@lists.launchpad.net :Web site: https://launchpad.net/~cisco-openstack :Copyright: 2011 Cisco Systems, Inc. @@ -86,7 +87,11 @@ Module Structure: /common - Modules common to the entire plugin /conf - All configuration files /db - Persistence framework + /models - Class(es) which tie the logical abstractions + to the physical topology /nexus - Nexus-specific modules + /segmentation - Implementation of segmentation manager, + e.g. VLAN Manager /tests - Tests specific to this plugin /ucs - UCS-specific modules @@ -100,9 +105,16 @@ Plugin Installation Instructions provider = quantum.plugins.cisco.l2network_plugin.L2Network -3. If you are not running Quantum on the same host as the OpenStack Cloud - Controller, you will need to change the db_ip_address configuration - in nova.ini. +3. Configure your OpenStack installation to use the 802.1qbh VIF driver and + Quantum-aware scheduler by editing the /etc/nova/nova.conf file with the + following entries: + +--scheduler_driver=quantum.plugins.cisco.nova.quantum_aware_scheduler.QuantumScheduler +--quantum_host=127.0.0.1 +--quantum_port=9696 +--libvirt_vif_driver=quantum.plugins.cisco.nova.vifdirect.Libvirt802dot1QbhDriver +--libvirt_vif_type=802.1Qbh + 4. If you want to turn on support for Cisco Nexus switches: 4a. Uncomment the nexus_plugin property in @@ -165,7 +177,39 @@ password=mySecretPasswordForNova username=admin password=mySecretPasswordForNexus -7. Start the Quantum service. If something doesn't work, verify that +7. Configure the UCS systems' information in your deployment by editing the + quantum/plugins/cisco/conf/ucs_inventory.ini file. You can configure multiple + UCSMs per deployment, multiple chasses per UCSM, and multiple blades per + chassis. Chassis ID and blade ID can be obtained from the UCSM (they will + typically numbers like 1, 2, 3, etc. + +[ucsm-1] +ip_address = +[[chassis-1]] +chassis_id = +[[[blade-1]]] +blade_id = +host_name = +[[[blade-2]]] +blade_id = +host_name = +[[[blade-3]]] +blade_id = +host_name = + +[ucsm-2] +ip_address = +[[chassis-1]] +chassis_id = +[[[blade-1]]] +blade_id = +host_name = +[[[blade-2]]] +blade_id = +host_name = + + +8. Start the Quantum service. If something doesn't work, verify that your configuration of each of the above files hasn't gone a little kaka. Once you've put right what once went wrong, leap on. From c4fcce4d73e53e1ec165d103ada11b2b6ba3a49f Mon Sep 17 00:00:00 2001 From: Sumit Naiksatam Date: Sat, 20 Aug 2011 22:39:16 -0700 Subject: [PATCH 17/39] Removed obsolete instructions from README. --- quantum/plugins/cisco/README | 49 ------------------------------------ 1 file changed, 49 deletions(-) diff --git a/quantum/plugins/cisco/README b/quantum/plugins/cisco/README index 095a69adc0..5b3d59a429 100755 --- a/quantum/plugins/cisco/README +++ b/quantum/plugins/cisco/README @@ -266,55 +266,6 @@ result the quantum/plugins/cisco/run_tests.py script. change later. Location quantum/plugins/cisco/tests/unit/test_cisco_extension.py -Additional installation required on Nova Compute ------------------------------------------------- -1. Create a table in the "nova" database for ports. This can be - accomplished with the following SQL statement: - -CREATE TABLE ports ( - port_id VARCHAR(255) PRIMARY KEY, - profile_name VARCHAR(255), - dynamic_vnic VARCHAR(255), - host VARCHAR(255), - instance_name VARCHAR(255), - instance_nic_name VARCHAR(255), - used TINYINT(1) -); - - Assuming you're using MySQL, you can run the following command from a - shell prompt on the Cloud Controller node to create the table: - -mysql -uroot -p nova -e 'create table ports (port_id VARCHAR(255) primary key, profile_name VARCHAR(255), dynamic_vnic VARCHAR(255), host VARCHAR(255), instance_name VARCHAR(255), instance_nic_name VARCHAR(255), used tinyint(1));' - -You'll be prompted for a password. - -2. A patch is available for the Cactus release in this branch: - https://code.launchpad.net/~snaiksat/quantum/cactus-ucs-support - replace the following file in your installation: - /usr/lib/python2.6/site-packages/nova/virt/libvirt_conn.py - with the file from the branch: - nova/virt/libvirt_conn.py - -3. Add the following file from the Cisco Nova branch: - nova/virt/cisco_ucs.py - to: - /usr/lib/python2.6/site-packages/nova/virt/cisco_ucs.py - -4. Add the 802.1Qbh specific libvirt template file, from: - nova/virt/libvirt-qbh.xml.template - to: - /usr/share/nova/libvirt-qbh.xml.template - -5. Edit /etc/nova.conf to set the libvirt XML template to the above template: - --libvirt_xml_template=/usr/share/nova/libvirt-qbh.xml.template - -6. Restart the nova-compute service. - - (Note that the requirement for the above patch is temporary and will go away - with the integration with OpenStack Diablo. A 802.1Qbh-specific VIF driver - will be made available as per the specification here: - http://wiki.openstack.org/network-refactoring#VIF_driver) - Bingo bango bongo! That's it! Thanks for taking the leap into Quantum. ...Oh, boy! From 294fe222ad43ee44bfe65b70dfac1ce8c639b4a6 Mon Sep 17 00:00:00 2001 From: Sumit Naiksatam Date: Mon, 22 Aug 2011 03:34:48 -0700 Subject: [PATCH 18/39] Refactoring of code to generalize inventory handling (enhancement). --- .../plugins/cisco/common/cisco_constants.py | 5 +- quantum/plugins/cisco/conf/plugins.ini | 4 + .../cisco/models/l2network_multi_blade.py | 156 ++++------ .../plugins/cisco/ucs/cisco_ucs_inventory.py | 269 +++++++++++++----- 4 files changed, 269 insertions(+), 165 deletions(-) diff --git a/quantum/plugins/cisco/common/cisco_constants.py b/quantum/plugins/cisco/common/cisco_constants.py index f2fa8805f7..eb9af68735 100644 --- a/quantum/plugins/cisco/common/cisco_constants.py +++ b/quantum/plugins/cisco/common/cisco_constants.py @@ -20,6 +20,7 @@ """ PLUGINS = 'PLUGINS' +INVENTORY = 'INVENTORY' PORT_STATE = 'port-state' PORT_UP = "ACTIVE" @@ -116,11 +117,13 @@ RHEL_DEVICE_NAME_REPFIX = "eth" UCS_PLUGIN = 'ucs_plugin' NEXUS_PLUGIN = 'nexus_plugin' +UCS_INVENTORY = 'ucs_inventory' +NEXUS_INVENTORY = 'nexus_inventory' PLUGIN_OBJ_REF = 'plugin-obj-ref' PARAM_LIST = 'param-list' -DEVICE_IP = 'device-ip' +DEVICE_IP = 'device_ip' NO_VLAN_ID = 0 diff --git a/quantum/plugins/cisco/conf/plugins.ini b/quantum/plugins/cisco/conf/plugins.ini index 8b4b476a0a..de98ccb18e 100644 --- a/quantum/plugins/cisco/conf/plugins.ini +++ b/quantum/plugins/cisco/conf/plugins.ini @@ -1,3 +1,7 @@ [PLUGINS] ucs_plugin=quantum.plugins.cisco.ucs.cisco_ucs_plugin.UCSVICPlugin #nexus_plugin=quantum.plugins.cisco.nexus.cisco_nexus_plugin.NexusPlugin + +[INVENTORY] +ucs_plugin=quantum.plugins.cisco.ucs.cisco_ucs_inventory.UCSInventory +#nexus_plugin=quantum.plugins.cisco.nexus.cisco_nexus_inventory.NexusInventory diff --git a/quantum/plugins/cisco/models/l2network_multi_blade.py b/quantum/plugins/cisco/models/l2network_multi_blade.py index aea084781f..a2d57e65ac 100644 --- a/quantum/plugins/cisco/models/l2network_multi_blade.py +++ b/quantum/plugins/cisco/models/l2network_multi_blade.py @@ -19,6 +19,7 @@ # """ +from copy import deepcopy import inspect import logging as LOG import platform @@ -29,10 +30,9 @@ from quantum.plugins.cisco.l2network_model_base import L2NetworkModelBase 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 -from quantum.plugins.cisco.ucs import cisco_ucs_inventory as ucsinv LOG.basicConfig(level=LOG.WARN) -LOG.getLogger(const.LOGGER_COMPONENT_NAME) +LOG.getLogger(__name__) class L2NetworkMultiBlade(L2NetworkModelBase): @@ -44,6 +44,7 @@ class L2NetworkMultiBlade(L2NetworkModelBase): All UCSM connected to a single Nexus Switch """ _plugins = {} + _inventory = {} def __init__(self): for key in conf.PLUGINS[const.PLUGINS].keys(): @@ -51,41 +52,45 @@ class L2NetworkMultiBlade(L2NetworkModelBase): conf.PLUGINS[const.PLUGINS][key]) LOG.debug("Loaded device plugin %s\n" % \ conf.PLUGINS[const.PLUGINS][key]) - - self._ucs_inventory = ucsinv.UCSInventory() + if key in conf.PLUGINS[const.INVENTORY].keys(): + self._inventory[key] = utils.import_object( + conf.PLUGINS[const.INVENTORY][key]) + LOG.debug("Loaded device inventory %s\n" % \ + conf.PLUGINS[const.INVENTORY][key]) def _func_name(self, offset=0): """Get the name of the calling function""" return inspect.stack()[1 + offset][3] - def _invoke_all_device_plugins(self, function_name, args, kwargs): - """Invoke all device plugins for this model implementation""" - for plugin_obj_ref in self._plugins.values(): - getattr(plugin_obj_ref, function_name)(*args, **kwargs) + def _invoke_plugin_per_device(self, plugin_key, function_name, args): + """Invoke only device plugin for all the devices in the system""" + if not plugin_key in self._plugins.keys(): + LOG.info("No %s Plugin loaded" % plugin_key) + LOG.info("%s: %s with args %s ignored" \ + % (plugin_key, function_name, args)) + return + device_params = self._invoke_inventory(plugin_key, function_name, + args) + device_ips = device_params[const.DEVICE_IP] + for device_ip in device_ips: + new_device_params = deepcopy(device_params) + new_device_params[const.DEVICE_IP] = device_ip + self._invoke_plugin(plugin_key, function_name, args, + new_device_params) - def _invoke_ucs_plugin(self, function_name, args, kwargs): - """Invoke only the UCS plugin""" - if const.UCS_PLUGIN in self._plugins.keys(): - getattr(self._plugins[const.UCS_PLUGIN], - function_name)(*args, **kwargs) + def _invoke_inventory(self, plugin_key, function_name, args): + """Invoke only the inventory implementation""" + if not plugin_key in self._inventory.keys(): + LOG.warn("No %s inventory loaded" % plugin_key) + LOG.warn("%s: %s with args %s ignored" \ + % (plugin_key, function_name, args)) + return + return getattr(self._inventory[plugin_key], function_name)(args) - def _invoke_ucs_plugin_per_device(self, function_name, args): - """Invoke only UCS plugin for all the UCSMs in the system""" - ucsm_ips = self._ucs_inventory.get_all_ucsms() - for ucsm_ip in ucsm_ips: - device_params = {const.DEVICE_IP: ucsm_ip} - self._invoke_ucs_plugin(function_name, args, device_params) - - def _invoke_nexus_plugin(self, function_name, args, kwargs): - """Invoke only the Nexus plugin""" - if const.NEXUS_PLUGIN in self._plugins.keys(): - getattr(self._plugins[const.NEXUS_PLUGIN], - function_name)(*args, **kwargs) - - def _invoke_nexus_plugin_per_device(self, function_name, args): - """Invoke only the nexus plugin for all the switches in the system""" - device_params = {const.DEVICE_IP: ""} - self._invoke_nexus_plugin(self._func_name(), args, device_params) + def _invoke_plugin(self, plugin_key, function_name, args, kwargs): + """Invoke only the device plugin""" + return getattr(self._plugins[plugin_key], function_name)(*args, + **kwargs) def get_all_networks(self, args): """Not implemented for this model""" @@ -93,13 +98,17 @@ class L2NetworkMultiBlade(L2NetworkModelBase): def create_network(self, args): """Support for the Quantum core API call""" - self._invoke_ucs_plugin_per_device(self._func_name(), args) - self._invoke_nexus_plugin_per_device(self._func_name(), args) + self._invoke_plugin_per_device(const.UCS_PLUGIN, self._func_name(), + args) + self._invoke_plugin_per_device(const.NEXUS_PLUGIN, + self._func_name(), args) def delete_network(self, args): """Support for the Quantum core API call""" - self._invoke_ucs_plugin_per_device(self._func_name(), args) - self._invoke_nexus_plugin_per_device(self._func_name(), args) + self._invoke_plugin_per_device(const.UCS_PLUGIN, self._func_name(), + args) + self._invoke_plugin_per_device(const.NEXUS_PLUGIN, + self._func_name(), args) def get_network_details(self, args): """Not implemented for this model""" @@ -107,8 +116,10 @@ class L2NetworkMultiBlade(L2NetworkModelBase): def rename_network(self, args): """Support for the Quantum core API call""" - self._invoke_ucs_plugin_per_device(self._func_name(), args) - self._invoke_nexus_plugin_per_device(self._func_name(), args) + self._invoke_plugin_per_device(const.UCS_PLUGIN, self._func_name(), + args) + self._invoke_plugin_per_device(const.NEXUS_PLUGIN, + self._func_name(), args) def get_all_ports(self, args): """Not implemented for this model""" @@ -116,35 +127,13 @@ class L2NetworkMultiBlade(L2NetworkModelBase): def create_port(self, args): """Support for the Quantum core API call""" - if not const.UCS_PLUGIN in self._plugins.keys(): - return - least_reserved_blade_dict = \ - self._ucs_inventory.get_least_reserved_blade() - if not least_reserved_blade_dict: - raise cexc.NoMoreNics() - ucsm_ip = least_reserved_blade_dict[const.LEAST_RSVD_BLADE_UCSM] - device_params = {const.DEVICE_IP: ucsm_ip, - const.UCS_INVENTORY: self._ucs_inventory, - const.LEAST_RSVD_BLADE_DICT:\ - least_reserved_blade_dict} - self._invoke_ucs_plugin(self._func_name(), args, device_params) + self._invoke_plugin_per_device(const.UCS_PLUGIN, self._func_name(), + args) def delete_port(self, args): """Support for the Quantum core API call""" - if not const.UCS_PLUGIN in self._plugins.keys(): - return - rsvd_info = \ - self._ucs_inventory.get_rsvd_blade_intf_by_port(args[0], - args[2]) - if not rsvd_info: - raise exc.PortNotFound(net_id=args[1], port_id=args[2]) - device_params = \ - {const.DEVICE_IP: rsvd_info[const.UCSM_IP], - const.UCS_INVENTORY: self._ucs_inventory, - const.CHASSIS_ID: rsvd_info[const.CHASSIS_ID], - const.BLADE_ID: rsvd_info[const.BLADE_ID], - const.BLADE_INTF_DN: rsvd_info[const.BLADE_INTF_DN]} - self._invoke_ucs_plugin(self._func_name(), args, device_params) + self._invoke_plugin_per_device(const.UCS_PLUGIN, self._func_name(), + args) def update_port(self, args): """Not implemented for this model""" @@ -156,51 +145,24 @@ class L2NetworkMultiBlade(L2NetworkModelBase): def plug_interface(self, args): """Support for the Quantum core API call""" - if not const.UCS_PLUGIN in self._plugins.keys(): - return - rsvd_info = \ - self._ucs_inventory.get_rsvd_blade_intf_by_port(args[0], - args[2]) - if not rsvd_info: - raise exc.PortNotFound(net_id=args[1], port_id=args[2]) - device_params = {const.DEVICE_IP: rsvd_info[const.UCSM_IP]} - self._invoke_ucs_plugin(self._func_name(), args, device_params) + self._invoke_plugin_per_device(const.UCS_PLUGIN, self._func_name(), + args) def unplug_interface(self, args): """Support for the Quantum core API call""" - if not const.UCS_PLUGIN in self._plugins.keys(): - return - rsvd_info = \ - self._ucs_inventory.get_rsvd_blade_intf_by_port(args[0], - args[2]) - if not rsvd_info: - raise exc.PortNotFound(net_id=args[1], port_id=args[2]) - device_params = {const.DEVICE_IP: rsvd_info[const.UCSM_IP]} - self._invoke_ucs_plugin(self._func_name(), args, device_params) + self._invoke_plugin_per_device(const.UCS_PLUGIN, self._func_name(), + args) def get_host(self, args): """Provides the hostname on which a dynamic vnic is reserved""" LOG.debug("get_host() called\n") - if not const.UCS_PLUGIN in self._plugins.keys(): - return - tenant_id = args[0] - instance_id = args[1] - host_name = self._ucs_inventory.get_host_name(tenant_id, instance_id) - host_list = {const.HOST_LIST: {const.HOST_1: host_name}} - return host_list + return self._invoke_inventory(const.UCS_PLUGIN, self._func_name(), + args) def get_instance_port(self, args): """ Get the portprofile name and the device namei for the dynamic vnic """ LOG.debug("get_instance_port() called\n") - if not const.UCS_PLUGIN in self._plugins.keys(): - return - tenant_id = args[0] - instance_id = args[1] - vif_id = args[2] - vif_info = self._ucs_inventory.get_instance_port(tenant_id, - instance_id, - vif_id) - vif_desc = {const.VIF_DESC: vif_info} - return vif_desc + return self._invoke_inventory(const.UCS_PLUGIN, self._func_name(), + args) diff --git a/quantum/plugins/cisco/ucs/cisco_ucs_inventory.py b/quantum/plugins/cisco/ucs/cisco_ucs_inventory.py index 09bbfe9f7c..7fcd65ba56 100644 --- a/quantum/plugins/cisco/ucs/cisco_ucs_inventory.py +++ b/quantum/plugins/cisco/ucs/cisco_ucs_inventory.py @@ -22,6 +22,8 @@ from copy import deepcopy import logging as LOG from quantum.common import exceptions as exc +from quantum.plugins.cisco.l2device_inventory_base \ + import L2NetworkDeviceInventoryBase from quantum.plugins.cisco.common import cisco_constants as const from quantum.plugins.cisco.common import cisco_credentials as cred from quantum.plugins.cisco.common import cisco_exceptions as cexc @@ -32,7 +34,7 @@ from quantum.plugins.cisco.ucs \ from quantum.plugins.cisco.ucs import cisco_ucs_network_driver LOG.basicConfig(level=LOG.WARN) -LOG.getLogger(const.LOGGER_COMPONENT_NAME) +LOG.getLogger(__name__) """ The _inventory data strcuture contains a nested disctioary: @@ -79,7 +81,7 @@ const.VIF_ID """ -class UCSInventory(object): +class UCSInventory(L2NetworkDeviceInventoryBase): """ Manages the state of all the UCS chasses, and blades in the system @@ -202,9 +204,85 @@ class UCSInventory(object): const.BLADE_UNRESERVED_INTF_COUNT: unreserved_counter} return blade_data - def get_all_ucsms(self): - """Get the IPs of all the UCSMs in the system""" - return self._inventory.keys() + def _get_all_ucsms(self): + """Return a list of the IPs of all the UCSMs in the system""" + return {const.DEVICE_IP: self._inventory.keys()} + + def _get_blade_for_port(self, args): + """ + Return the a dict with IP address of the blade + on which a dynamic vnic was reserved for this port + """ + tenant_id = args[0] + net_id = args[1] + port_id = args[2] + rsvd_info = self.get_rsvd_blade_intf_by_port(tenant_id, port_id) + if not rsvd_info: + raise exc.PortNotFound(net_id=net_id, port_id=port_id) + device_params = {const.DEVICE_IP: [rsvd_info[const.UCSM_IP]]} + return device_params + + def _get_host_name_for_rsvd_intf(self, tenant_id, instance_id): + """ + Return the hostname of the blade with a reserved instance + for this tenant + """ + for ucsm_ip in self._inventory_state.keys(): + ucsm = self._inventory_state[ucsm_ip] + for chassis_id in ucsm.keys(): + for blade_id in ucsm[chassis_id]: + blade_data = ucsm[chassis_id][blade_id] + blade_intf_data = blade_data[const.BLADE_INTF_DATA] + for blade_intf in blade_intf_data.keys(): + if blade_intf_data[blade_intf]\ + [const.BLADE_INTF_RESERVATION] == \ + const.BLADE_INTF_RESERVED and \ + blade_intf_data[blade_intf]\ + [const.TENANTID] == tenant_id and \ + blade_intf_data[blade_intf]\ + [const.INSTANCE_ID] == None: + blade_intf_data[blade_intf]\ + [const.INSTANCE_ID] = instance_id + host_name = self._get_host_name(ucsm_ip, + chassis_id, + blade_id) + port_binding = udb.get_portbinding_dn(blade_intf) + port_id = port_binding[const.PORTID] + udb.update_portbinding(port_id, + instance_id=instance_id) + return host_name + return None + + def _get_instance_port(self, tenant_id, instance_id, vif_id=None): + """ + Return the device name for a reserved interface + """ + for ucsm_ip in self._inventory_state.keys(): + ucsm = self._inventory_state[ucsm_ip] + for chassis_id in ucsm.keys(): + for blade_id in ucsm[chassis_id]: + blade_data = ucsm[chassis_id][blade_id] + blade_intf_data = blade_data[const.BLADE_INTF_DATA] + for blade_intf in blade_intf_data.keys(): + if blade_intf_data[blade_intf]\ + [const.BLADE_INTF_RESERVATION] == \ + const.BLADE_INTF_RESERVED and \ + blade_intf_data[blade_intf]\ + [const.TENANTID] == tenant_id and \ + blade_intf_data[blade_intf]\ + [const.INSTANCE_ID] == instance_id: + blade_intf_data[blade_intf][const.VIF_ID] = \ + vif_id + port_binding = udb.get_portbinding_dn(blade_intf) + port_id = port_binding[const.PORTID] + udb.update_portbinding(port_id, + vif_id=vif_id) + device_name = blade_intf_data[blade_intf]\ + [const.BLADE_INTF_RHEL_DEVICE_NAME] + profile_name = port_binding[const.PORTPROFILENAME] + return {const.DEVICENAME: device_name, + const.UCSPROFILE: profile_name} + return None def reload_inventory(self): """Reload the inventory from a conf file""" @@ -385,69 +463,126 @@ class UCSInventory(object): return blade_intf_info return None - def get_host_name(self, tenant_id, instance_id): - """ - Return the hostname of the blade with a reserved instance - for this tenant - """ - for ucsm_ip in self._inventory_state.keys(): - ucsm = self._inventory_state[ucsm_ip] - for chassis_id in ucsm.keys(): - for blade_id in ucsm[chassis_id]: - blade_data = ucsm[chassis_id][blade_id] - blade_intf_data = blade_data[const.BLADE_INTF_DATA] - for blade_intf in blade_intf_data.keys(): - if blade_intf_data[blade_intf]\ - [const.BLADE_INTF_RESERVATION] == \ - const.BLADE_INTF_RESERVED and \ - blade_intf_data[blade_intf]\ - [const.TENANTID] == tenant_id and \ - blade_intf_data[blade_intf]\ - [const.INSTANCE_ID] == None: - blade_intf_data[blade_intf]\ - [const.INSTANCE_ID] = instance_id - host_name = self._get_host_name(ucsm_ip, - chassis_id, - blade_id) - port_binding = udb.get_portbinding_dn(blade_intf) - port_id = port_binding[const.PORTID] - udb.update_portbinding(port_id, - instance_id=instance_id) - return host_name - return None - - def get_instance_port(self, tenant_id, instance_id, vif_id=None): - """ - Return the device name for a reserved interface - """ - for ucsm_ip in self._inventory_state.keys(): - ucsm = self._inventory_state[ucsm_ip] - for chassis_id in ucsm.keys(): - for blade_id in ucsm[chassis_id]: - blade_data = ucsm[chassis_id][blade_id] - blade_intf_data = blade_data[const.BLADE_INTF_DATA] - for blade_intf in blade_intf_data.keys(): - if blade_intf_data[blade_intf]\ - [const.BLADE_INTF_RESERVATION] == \ - const.BLADE_INTF_RESERVED and \ - blade_intf_data[blade_intf]\ - [const.TENANTID] == tenant_id and \ - blade_intf_data[blade_intf]\ - [const.INSTANCE_ID] == instance_id: - blade_intf_data[blade_intf][const.VIF_ID] = \ - vif_id - port_binding = udb.get_portbinding_dn(blade_intf) - port_id = port_binding[const.PORTID] - udb.update_portbinding(port_id, - vif_id=vif_id) - device_name = blade_intf_data[blade_intf]\ - [const.BLADE_INTF_RHEL_DEVICE_NAME] - profile_name = port_binding[const.PORTPROFILENAME] - return {const.DEVICENAME: device_name, - const.UCSPROFILE: profile_name} - return None - def add_blade(self, ucsm_ip, chassis_id, blade_id): """Add a blade to the inventory""" # TODO (Sumit) pass + + def get_all_networks(self, args): + """Return all UCSM IPs""" + LOG.debug("get_all_networks() called\n") + return self._get_all_ucsms() + + def create_network(self, args): + """Return all UCSM IPs""" + LOG.debug("create_network() called\n") + return self._get_all_ucsms() + + def delete_network(self, args): + """Return all UCSM IPs""" + LOG.debug("delete_network() called\n") + return self._get_all_ucsms() + + def get_network_details(self, args): + """Return all UCSM IPs""" + LOG.debug("get_network_details() called\n") + return self._get_all_ucsms() + + def rename_network(self, args): + """Return all UCSM IPs""" + LOG.debug("rename_network() called\n") + return self._get_all_ucsms() + + def get_all_ports(self, args): + """Return all UCSM IPs""" + LOG.debug("get_all_ports() called\n") + return self._get_all_ucsms() + + def create_port(self, args): + """ + Return the a dict with information of the blade + on which a dynamic vnic is available + """ + LOG.debug("create_port() called\n") + least_reserved_blade_dict = self.get_least_reserved_blade() + if not least_reserved_blade_dict: + raise cexc.NoMoreNics() + ucsm_ip = least_reserved_blade_dict[const.LEAST_RSVD_BLADE_UCSM] + device_params = {const.DEVICE_IP: [ucsm_ip], + const.UCS_INVENTORY: self, + const.LEAST_RSVD_BLADE_DICT:\ + least_reserved_blade_dict} + return device_params + + def delete_port(self, args): + """ + Return the a dict with information of the blade + on which a dynamic vnic was reserved for this port + """ + LOG.debug("delete_port() called\n") + tenant_id = args[0] + net_id = args[1] + port_id = args[2] + rsvd_info = self.get_rsvd_blade_intf_by_port(tenant_id, port_id) + if not rsvd_info: + raise exc.PortNotFound(net_id=net_id, port_id=port_id) + device_params = \ + {const.DEVICE_IP: [rsvd_info[const.UCSM_IP]], + const.UCS_INVENTORY: self, + const.CHASSIS_ID: rsvd_info[const.CHASSIS_ID], + const.BLADE_ID: rsvd_info[const.BLADE_ID], + const.BLADE_INTF_DN: rsvd_info[const.BLADE_INTF_DN]} + return device_params + + def update_port(self, args): + """ + Return the a dict with IP address of the blade + on which a dynamic vnic was reserved for this port + """ + LOG.debug("update_port() called\n") + return self._get_blade_for_port(args) + + def get_port_details(self, args): + """ + Return the a dict with IP address of the blade + on which a dynamic vnic was reserved for this port + """ + LOG.debug("get_port_details() called\n") + return self._get_blade_for_port(args) + + def plug_interface(self, args): + """ + Return the a dict with IP address of the blade + on which a dynamic vnic was reserved for this port + """ + LOG.debug("plug_interface() called\n") + return self._get_blade_for_port(args) + + def unplug_interface(self, args): + """ + Return the a dict with IP address of the blade + on which a dynamic vnic was reserved for this port + """ + LOG.debug("unplug_interface() called\n") + return self._get_blade_for_port(args) + + def get_host(self, args): + """Provides the hostname on which a dynamic vnic is reserved""" + LOG.debug("get_host() called\n") + tenant_id = args[0] + instance_id = args[1] + host_name = self._get_host_name_for_rsvd_intf(tenant_id, instance_id) + host_list = {const.HOST_LIST: {const.HOST_1: host_name}} + return host_list + + def get_instance_port(self, args): + """ + Get the portprofile name and the device name for the dynamic vnic + """ + LOG.debug("get_instance_port() called\n") + tenant_id = args[0] + instance_id = args[1] + vif_id = args[2] + vif_info = self._get_instance_port(tenant_id, instance_id, vif_id) + vif_desc = {const.VIF_DESC: vif_info} + return vif_desc From 88dad10e4d7c60e922fc9da7348713a94dabe3cf Mon Sep 17 00:00:00 2001 From: Sumit Naiksatam Date: Mon, 22 Aug 2011 04:16:03 -0700 Subject: [PATCH 19/39] Missed adding a file earlier, fixed a small issue. --- .../plugins/cisco/l2device_inventory_base.py | 343 ++++++++++++++++++ .../cisco/models/l2network_multi_blade.py | 17 +- 2 files changed, 354 insertions(+), 6 deletions(-) create mode 100644 quantum/plugins/cisco/l2device_inventory_base.py diff --git a/quantum/plugins/cisco/l2device_inventory_base.py b/quantum/plugins/cisco/l2device_inventory_base.py new file mode 100644 index 0000000000..9ecbed3feb --- /dev/null +++ b/quantum/plugins/cisco/l2device_inventory_base.py @@ -0,0 +1,343 @@ +""" +# 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: Sumit Naiksatam, Cisco Systems, Inc. +# +""" + +import inspect +from abc import ABCMeta, abstractmethod + + +class L2NetworkDeviceInventoryBase(object): + """ + Base class for L2 Network Device Inventory + This is used by the L2Nework Model to get information about + the actual devices of a particular type in a given deployment. + For instance, an implementation in the context of UCS will + know what UCSMs, chasses, blades, and dynamic vnics are + present in a particular deployment. + Similarly, an implementation in the context of Nexus switches + will know which switches are present in the system, and how they + are interconnected to other switches/devices. + """ + + __metaclass__ = ABCMeta + + @abstractmethod + def get_all_networks(self, args): + """ + Returns a dictionary containing the first element as a device + IP address list. The model then invokes the device-specific plugin + for each device IP in that list. This is followed by zero or more + key-value pairs (specific to each operation, device type, and + deployment. + The model implementation may or may not process the returned + values, but needs to pass them to the device-specific plugin. + Since the device-specific plugin and this inventory implementation + are assumed to be implemented by the same entity, the + device-sepcific knows how to process this dictionary. + :returns: a dictionary with the following signature: + {'device_ip': [] + 'key-1': "value 1", + ... + 'key-n': "value n" + } + :raises: + """ + pass + + @abstractmethod + def create_network(self, args): + """ + Returns a dictionary containing the first element as a device + IP address list. The model then invokes the device-specific plugin + for each device IP in that list. This is followed by zero or more + key-value pairs (specific to each operation, device type, and + deployment. + The model implementation may or may not process the returned + values, but needs to pass them to the device-specific plugin. + Since the device-specific plugin and this inventory implementation + are assumed to be implemented by the same entity, the + device-sepcific knows how to process this dictionary. + :returns: a dictionary with the following signature: + {'device_ip': [] + 'key-1': "value 1", + ... + 'key-n': "value n" + } + :raises: + """ + pass + + @abstractmethod + def delete_network(self, args): + """ + Returns a dictionary containing the first element as a device + IP address list. The model then invokes the device-specific plugin + for each device IP in that list. This is followed by zero or more + key-value pairs (specific to each operation, device type, and + deployment. + The model implementation may or may not process the returned + values, but needs to pass them to the device-specific plugin. + Since the device-specific plugin and this inventory implementation + are assumed to be implemented by the same entity, the + device-sepcific knows how to process this dictionary. + :returns: a dictionary with the following signature: + {'device_ip': [] + 'key-1': "value 1", + ... + 'key-n': "value n" + } + :raises: + """ + pass + + @abstractmethod + def get_network_details(self, args): + """ + Returns a dictionary containing the first element as a device + IP address list. The model then invokes the device-specific plugin + for each device IP in that list. This is followed by zero or more + key-value pairs (specific to each operation, device type, and + deployment. + The model implementation may or may not process the returned + values, but needs to pass them to the device-specific plugin. + Since the device-specific plugin and this inventory implementation + are assumed to be implemented by the same entity, the + device-sepcific knows how to process this dictionary. + :returns: a dictionary with the following signature: + {'device_ip': [] + 'key-1': "value 1", + ... + 'key-n': "value n" + } + :raises: + """ + pass + + @abstractmethod + def rename_network(self, args): + """ + Returns a dictionary containing the first element as a device + IP address list. The model then invokes the device-specific plugin + for each device IP in that list. This is followed by zero or more + key-value pairs (specific to each operation, device type, and + deployment. + The model implementation may or may not process the returned + values, but needs to pass them to the device-specific plugin. + Since the device-specific plugin and this inventory implementation + are assumed to be implemented by the same entity, the + device-sepcific knows how to process this dictionary. + :returns: a dictionary with the following signature: + {'device_ip': [] + 'key-1': "value 1", + ... + 'key-n': "value n" + } + :raises: + """ + pass + + @abstractmethod + def get_all_ports(self, args): + """ + Returns a dictionary containing the first element as a device + IP address list. The model then invokes the device-specific plugin + for each device IP in that list. This is followed by zero or more + key-value pairs (specific to each operation, device type, and + deployment. + The model implementation may or may not process the returned + values, but needs to pass them to the device-specific plugin. + Since the device-specific plugin and this inventory implementation + are assumed to be implemented by the same entity, the + device-sepcific knows how to process this dictionary. + :returns: a dictionary with the following signature: + {'device_ip': [] + 'key-1': "value 1", + ... + 'key-n': "value n" + } + :raises: + """ + pass + + @abstractmethod + def create_port(self, args): + """ + Returns a dictionary containing the first element as a device + IP address list. The model then invokes the device-specific plugin + for each device IP in that list. This is followed by zero or more + key-value pairs (specific to each operation, device type, and + deployment. + The model implementation may or may not process the returned + values, but needs to pass them to the device-specific plugin. + Since the device-specific plugin and this inventory implementation + are assumed to be implemented by the same entity, the + device-sepcific knows how to process this dictionary. + :returns: a dictionary with the following signature: + {'device_ip': [] + 'key-1': "value 1", + ... + 'key-n': "value n" + } + :raises: + """ + pass + + @abstractmethod + def delete_port(self, args): + """ + Returns a dictionary containing the first element as a device + IP address list. The model then invokes the device-specific plugin + for each device IP in that list. This is followed by zero or more + key-value pairs (specific to each operation, device type, and + deployment. + The model implementation may or may not process the returned + values, but needs to pass them to the device-specific plugin. + Since the device-specific plugin and this inventory implementation + are assumed to be implemented by the same entity, the + device-sepcific knows how to process this dictionary. + :returns: a dictionary with the following signature: + {'device_ip': [] + 'key-1': "value 1", + ... + 'key-n': "value n" + } + :raises: + """ + pass + + @abstractmethod + def update_port(self, args): + """ + Returns a dictionary containing the first element as a device + IP address list. The model then invokes the device-specific plugin + for each device IP in that list. This is followed by zero or more + key-value pairs (specific to each operation, device type, and + deployment. + The model implementation may or may not process the returned + values, but needs to pass them to the device-specific plugin. + Since the device-specific plugin and this inventory implementation + are assumed to be implemented by the same entity, the + device-sepcific knows how to process this dictionary. + :returns: a dictionary with the following signature: + {'device_ip': [] + 'key-1': "value 1", + ... + 'key-n': "value n" + } + :raises: + """ + pass + + @abstractmethod + def get_port_details(self, args): + """ + Returns a dictionary containing the first element as a device + IP address list. The model then invokes the device-specific plugin + for each device IP in that list. This is followed by zero or more + key-value pairs (specific to each operation, device type, and + deployment. + The model implementation may or may not process the returned + values, but needs to pass them to the device-specific plugin. + Since the device-specific plugin and this inventory implementation + are assumed to be implemented by the same entity, the + device-sepcific knows how to process this dictionary. + :returns: a dictionary with the following signature: + {'device_ip': [] + 'key-1': "value 1", + ... + 'key-n': "value n" + } + :raises: + """ + pass + + @abstractmethod + def plug_interface(self, args): + """ + Returns a dictionary containing the first element as a device + IP address list. The model then invokes the device-specific plugin + for each device IP in that list. This is followed by zero or more + key-value pairs (specific to each operation, device type, and + deployment. + The model implementation may or may not process the returned + values, but needs to pass them to the device-specific plugin. + Since the device-specific plugin and this inventory implementation + are assumed to be implemented by the same entity, the + device-sepcific knows how to process this dictionary. + :returns: a dictionary with the following signature: + {'device_ip': [] + 'key-1': "value 1", + ... + 'key-n': "value n" + } + :raises: + """ + pass + + @abstractmethod + def unplug_interface(self, args): + """ + Returns a dictionary containing the first element as a device + IP address list. The model then invokes the device-specific plugin + for each device IP in that list. This is followed by zero or more + key-value pairs (specific to each operation, device type, and + deployment. + The model implementation may or may not process the returned + values, but needs to pass them to the device-specific plugin. + Since the device-specific plugin and this inventory implementation + are assumed to be implemented by the same entity, the + device-sepcific knows how to process this dictionary. + :returns: a dictionary with the following signature: + {'device_ip': [] + 'key-1': "value 1", + ... + 'key-n': "value n" + } + :raises: + """ + pass + + @classmethod + def __subclasshook__(cls, klass): + """ + The __subclasshook__ method is a class method + that will be called everytime a class is tested + using issubclass(klass, Plugin). + In that case, it will check that every method + marked with the abstractmethod decorator is + provided by the plugin class. + """ + if cls is L2NetworkDeviceInventoryBase: + for method in cls.__abstractmethods__: + method_ok = False + for base in klass.__mro__: + if method in base.__dict__: + fn_obj = base.__dict__[method] + if inspect.isfunction(fn_obj): + abstract_fn_obj = cls.__dict__[method] + arg_count = fn_obj.func_code.co_argcount + expected_arg_count = \ + abstract_fn_obj.func_code.co_argcount + method_ok = arg_count == expected_arg_count + if method_ok: + continue + return NotImplemented + return True + return NotImplemented diff --git a/quantum/plugins/cisco/models/l2network_multi_blade.py b/quantum/plugins/cisco/models/l2network_multi_blade.py index a2d57e65ac..9f8958b2bf 100644 --- a/quantum/plugins/cisco/models/l2network_multi_blade.py +++ b/quantum/plugins/cisco/models/l2network_multi_blade.py @@ -72,11 +72,15 @@ class L2NetworkMultiBlade(L2NetworkModelBase): device_params = self._invoke_inventory(plugin_key, function_name, args) device_ips = device_params[const.DEVICE_IP] - for device_ip in device_ips: - new_device_params = deepcopy(device_params) - new_device_params[const.DEVICE_IP] = device_ip + if not device_ips: self._invoke_plugin(plugin_key, function_name, args, - new_device_params) + device_params) + else: + for device_ip in device_ips: + new_device_params = deepcopy(device_params) + new_device_params[const.DEVICE_IP] = device_ip + self._invoke_plugin(plugin_key, function_name, args, + new_device_params) def _invoke_inventory(self, plugin_key, function_name, args): """Invoke only the inventory implementation""" @@ -84,8 +88,9 @@ class L2NetworkMultiBlade(L2NetworkModelBase): LOG.warn("No %s inventory loaded" % plugin_key) LOG.warn("%s: %s with args %s ignored" \ % (plugin_key, function_name, args)) - return - return getattr(self._inventory[plugin_key], function_name)(args) + return {const.DEVICE_IP: []} + else: + return getattr(self._inventory[plugin_key], function_name)(args) def _invoke_plugin(self, plugin_key, function_name, args, kwargs): """Invoke only the device plugin""" From 54fe0bceed186dd68e1fd6fb57ac90a4e50557fb Mon Sep 17 00:00:00 2001 From: Sumit Naiksatam Date: Mon, 22 Aug 2011 12:15:35 -0700 Subject: [PATCH 20/39] Fixed loading of Nexus DB tables; moved imports to l2nework_db.py, changes discussed & approved by Rohit. --- quantum/plugins/cisco/db/l2network_db.py | 2 ++ quantum/plugins/cisco/l2network_plugin.py | 1 - 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/quantum/plugins/cisco/db/l2network_db.py b/quantum/plugins/cisco/db/l2network_db.py index 8f85afb55e..6196fe17ea 100644 --- a/quantum/plugins/cisco/db/l2network_db.py +++ b/quantum/plugins/cisco/db/l2network_db.py @@ -24,6 +24,8 @@ from quantum.plugins.cisco.common import cisco_exceptions as c_exc import l2network_models import logging as LOG import quantum.plugins.cisco.db.api as db +from quantum.plugins.cisco.db import nexus_db as ndb +from quantum.plugins.cisco.db import ucs_db as udb def initialize(): diff --git a/quantum/plugins/cisco/l2network_plugin.py b/quantum/plugins/cisco/l2network_plugin.py index 225468bd8e..153f39a468 100644 --- a/quantum/plugins/cisco/l2network_plugin.py +++ b/quantum/plugins/cisco/l2network_plugin.py @@ -33,7 +33,6 @@ from quantum.plugins.cisco.common import cisco_credentials as cred 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 -from quantum.plugins.cisco.db import ucs_db as udb LOG.basicConfig(level=LOG.WARN) LOG.getLogger(const.LOGGER_COMPONENT_NAME) From efe6f0e0304dbdf9b6a45a648a48a29c147edb0f Mon Sep 17 00:00:00 2001 From: Sumit Naiksatam Date: Wed, 24 Aug 2011 04:16:15 -0700 Subject: [PATCH 21/39] Fixed a bug in the initialization of the UCS inventory; fixed another bug in deleting a port. --- .../plugins/cisco/common/cisco_constants.py | 1 + quantum/plugins/cisco/l2network_plugin.py | 7 +- .../plugins/cisco/ucs/cisco_ucs_inventory.py | 81 +++++++++++++------ 3 files changed, 62 insertions(+), 27 deletions(-) diff --git a/quantum/plugins/cisco/common/cisco_constants.py b/quantum/plugins/cisco/common/cisco_constants.py index eb9af68735..edc3e2ea1f 100644 --- a/quantum/plugins/cisco/common/cisco_constants.py +++ b/quantum/plugins/cisco/common/cisco_constants.py @@ -141,6 +141,7 @@ HOST_NAME = 'host_name' INSTANCE_ID = 'instance_id' VIF_ID = 'vif_id' +PROJECT_ID = 'project_id' UCS_INVENTORY = 'ucs_inventory' LEAST_RSVD_BLADE_DICT = 'least_rsvd_blade_dict' diff --git a/quantum/plugins/cisco/l2network_plugin.py b/quantum/plugins/cisco/l2network_plugin.py index 153f39a468..bdeedb521c 100644 --- a/quantum/plugins/cisco/l2network_plugin.py +++ b/quantum/plugins/cisco/l2network_plugin.py @@ -107,7 +107,7 @@ class L2Network(QuantumPluginBase): if port[const.INTERFACEID]: raise exc.NetworkInUse(net_id=net_id) for port in ports_on_net: - self.delete_port(tenant_id, net_id, port[const.PORTID]) + self.delete_port(tenant_id, net_id, port[const.UUID]) self._invoke_device_plugins(self._func_name(), [tenant_id, net_id]) net_dict = cutil.make_net_dict(net[const.UUID], @@ -488,9 +488,10 @@ class L2Network(QuantumPluginBase): def get_host(self, tenant_id, instance_id, instance_desc): """Provides the hostname on which a dynamic vnic is reserved""" LOG.debug("get_host() called\n") - return self._invoke_device_plugins(self._func_name(), [tenant_id, + host_list = self._invoke_device_plugins(self._func_name(), [tenant_id, instance_id, instance_desc]) + return host_list def get_instance_port(self, tenant_id, instance_id, instance_desc): """ @@ -508,7 +509,7 @@ class L2Network(QuantumPluginBase): """ All device-specific calls are delegated to the model """ - getattr(self._model, function_name)(args) + return getattr(self._model, function_name)(args) def _get_vlan_for_tenant(self, tenant_id, net_name): """Get vlan ID""" diff --git a/quantum/plugins/cisco/ucs/cisco_ucs_inventory.py b/quantum/plugins/cisco/ucs/cisco_ucs_inventory.py index 7fcd65ba56..7b13982d66 100644 --- a/quantum/plugins/cisco/ucs/cisco_ucs_inventory.py +++ b/quantum/plugins/cisco/ucs/cisco_ucs_inventory.py @@ -99,6 +99,7 @@ class UCSInventory(L2NetworkDeviceInventoryBase): """Load the inventory from a config file""" inventory = deepcopy(conf.INVENTORY) LOG.info("Loaded UCS inventory: %s\n" % inventory) + LOG.info("Building UCS inventory state (this may take a while)...") for ucsm in inventory.keys(): ucsm_ip = inventory[ucsm][const.IP_ADDRESS] @@ -132,12 +133,17 @@ class UCSInventory(L2NetworkDeviceInventoryBase): blade_intf_data = self._client.get_blade_data(chassis_id, blade_id, ucsm_ip, ucsm_username, ucsm_password) - LOG.info("Building UCS inventory state (this may take a while)...") unreserved_counter = 0 for blade_intf in blade_intf_data.keys(): dist_name = blade_intf_data[blade_intf][const.BLADE_INTF_DN] + # We first make a pass through the state in UCSM + # If a particular interface is showing as being allocated in + # UCSM then it is definitely being used and so should be + # marked as reserved, else we temporarily mark it as unreserved + # based on the UCSM state, but may later change it if a port + # association is found in the DB if (blade_intf_data[blade_intf][const.BLADE_INTF_LINK_STATE] == \ const.BLADE_INTF_STATE_UNALLOCATED or \ blade_intf_data[blade_intf][const.BLADE_INTF_LINK_STATE] == \ @@ -155,24 +161,30 @@ class UCSInventory(L2NetworkDeviceInventoryBase): else: blade_intf_data[blade_intf][const.BLADE_INTF_RESERVATION] = \ const.BLADE_INTF_RESERVED - port_binding = udb.get_portbinding_dn(dist_name) - if not port_binding: - blade_intf_data[blade_intf][const.TENANTID] = None - blade_intf_data[blade_intf][const.PORTID] = None - blade_intf_data[blade_intf][const.PROFILE_ID] = None - blade_intf_data[blade_intf][const.INSTANCE_ID] = None - blade_intf_data[blade_intf][const.VIF_ID] = None - else: - blade_intf_data[blade_intf][const.TENANTID] = \ - port_binding[const.TENANTID] - blade_intf_data[blade_intf][const.PORTID] = \ - port_binding[const.PORTID] - blade_intf_data[blade_intf][const.PROFILE_ID] = \ - port_binding[const.PORTPROFILENAME] - blade_intf_data[blade_intf][const.INSTANCE_ID] = \ - port_binding[const.INSTANCE_ID] - blade_intf_data[blade_intf][const.VIF_ID] = \ - port_binding[const.VIF_ID] + + port_binding = udb.get_portbinding_dn(dist_name) + if port_binding: + # We have found a port binding for this interface in the DB, + # so we have earlier marked this interface as unreserved, we + # need to change it, and also load the state from the DB for + # other associations + if blade_intf_data[blade_intf]\ + [const.BLADE_INTF_RESERVATION] == \ + const.BLADE_INTF_UNRESERVED: + unreserved_counter -= 1 + blade_intf_data[blade_intf]\ + [const.BLADE_INTF_RESERVATION] = \ + const.BLADE_INTF_RESERVED + blade_intf_data[blade_intf][const.TENANTID] = \ + port_binding[const.TENANTID] + blade_intf_data[blade_intf][const.PORTID] = \ + port_binding[const.PORTID] + blade_intf_data[blade_intf][const.PROFILE_ID] = \ + port_binding[const.PORTPROFILENAME] + blade_intf_data[blade_intf][const.INSTANCE_ID] = \ + port_binding[const.INSTANCE_ID] + blade_intf_data[blade_intf][const.VIF_ID] = \ + port_binding[const.VIF_ID] blade_data = {const.BLADE_INTF_DATA: blade_intf_data, const.BLADE_UNRESERVED_INTF_COUNT: unreserved_counter} @@ -234,6 +246,7 @@ class UCSInventory(L2NetworkDeviceInventoryBase): blade_data = ucsm[chassis_id][blade_id] blade_intf_data = blade_data[const.BLADE_INTF_DATA] for blade_intf in blade_intf_data.keys(): + tmp = deepcopy(blade_intf_data[blade_intf]) if blade_intf_data[blade_intf]\ [const.BLADE_INTF_RESERVATION] == \ const.BLADE_INTF_RESERVED and \ @@ -251,6 +264,8 @@ class UCSInventory(L2NetworkDeviceInventoryBase): udb.update_portbinding(port_id, instance_id=instance_id) return host_name + LOG.warn("Could not find a reserved dynamic nic for tenant: %s" % + tenant_id) return None def _get_instance_port(self, tenant_id, instance_id, vif_id=None): @@ -280,8 +295,17 @@ class UCSInventory(L2NetworkDeviceInventoryBase): device_name = blade_intf_data[blade_intf]\ [const.BLADE_INTF_RHEL_DEVICE_NAME] profile_name = port_binding[const.PORTPROFILENAME] - return {const.DEVICENAME: device_name, - const.UCSPROFILE: profile_name} + dynamicnic_details = \ + {const.DEVICENAME: device_name, + const.UCSPROFILE: profile_name} + LOG.debug("Found reserved dynamic nic: %s" \ + "associated with port %s" % + (blade_intf_data[blade_intf], port_id)) + LOG.debug("Returning dynamic nic details: %s" % + dynamicnic_details) + return dynamicnic_details + LOG.warn("Could not find a reserved dynamic nic for tenant: %s" % + tenant_id) return None def reload_inventory(self): @@ -334,6 +358,7 @@ class UCSInventory(L2NetworkDeviceInventoryBase): least_reserved_blade_data = blade_data if unreserved_interface_count == 0: + LOG.warn("No more dynamic nics available for reservation") return False least_reserved_blade_dict = \ @@ -341,6 +366,8 @@ class UCSInventory(L2NetworkDeviceInventoryBase): const.LEAST_RSVD_BLADE_CHASSIS: least_reserved_blade_chassis, const.LEAST_RSVD_BLADE_ID: least_reserved_blade_id, const.LEAST_RSVD_BLADE_DATA: least_reserved_blade_data} + LOG.debug("Found dynamic nic %s available for reservation", + least_reserved_blade_dict) return least_reserved_blade_dict def reserve_blade_interface(self, ucsm_ip, chassis_id, blade_id, @@ -412,6 +439,8 @@ class UCSInventory(L2NetworkDeviceInventoryBase): LOG.debug("Reserved blade interface: %s\n" % reserved_nic_dict) return reserved_nic_dict + LOG.warn("Dynamic nic %s could not be reserved for port-id: %s" % + (blade_data_dict, port_id)) return False def unreserve_blade_interface(self, ucsm_ip, chassis_id, blade_id, @@ -461,6 +490,8 @@ class UCSInventory(L2NetworkDeviceInventoryBase): const.BLADE_INTF_DN: interface_dn} return blade_intf_info + LOG.warn("Could not find a reserved nic for tenant: %s port: %s" % + (tenant_id, port_id)) return None def add_blade(self, ucsm_ip, chassis_id, blade_id): @@ -569,10 +600,11 @@ class UCSInventory(L2NetworkDeviceInventoryBase): def get_host(self, args): """Provides the hostname on which a dynamic vnic is reserved""" LOG.debug("get_host() called\n") - tenant_id = args[0] instance_id = args[1] + tenant_id = args[2][const.PROJECT_ID] host_name = self._get_host_name_for_rsvd_intf(tenant_id, instance_id) host_list = {const.HOST_LIST: {const.HOST_1: host_name}} + LOG.debug("host_list is: %s" % host_list) return host_list def get_instance_port(self, args): @@ -580,9 +612,10 @@ class UCSInventory(L2NetworkDeviceInventoryBase): Get the portprofile name and the device name for the dynamic vnic """ LOG.debug("get_instance_port() called\n") - tenant_id = args[0] instance_id = args[1] - vif_id = args[2] + tenant_id = args[2][const.PROJECT_ID] + 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 From b5fd8f8075302b3aa56a47d98b56e922022fd803 Mon Sep 17 00:00:00 2001 From: rohitagarwalla Date: Wed, 24 Aug 2011 13:36:38 -0700 Subject: [PATCH 22/39] putting in db support for creds and qos --- .../plugins/cisco/common/cisco_exceptions.py | 15 ++ quantum/plugins/cisco/db/l2network_db.py | 176 +++++++++++++++++- quantum/plugins/cisco/db/l2network_models.py | 42 +++++ 3 files changed, 231 insertions(+), 2 deletions(-) diff --git a/quantum/plugins/cisco/common/cisco_exceptions.py b/quantum/plugins/cisco/common/cisco_exceptions.py index d257f5ee18..0ef83528c5 100644 --- a/quantum/plugins/cisco/common/cisco_exceptions.py +++ b/quantum/plugins/cisco/common/cisco_exceptions.py @@ -100,11 +100,26 @@ class QoSLevelInvalidDelete(exceptions.QuantumException): "for tenant %(tenant_id)s since association exists") +class QosNameAlreadyExists(exceptions.QuantumException): + message = _("QoS level with name %(qos_name)s already exists " \ + "for tenant %(tenant_id)s") + + class CredentialNotFound(exceptions.QuantumException): message = _("Credential %(credential_id)s could not be found " \ "for tenant %(tenant_id)s") +class CredentialNameNotFound(exceptions.QuantumException): + message = _("Credential %(credential_name)s could not be found " \ + "for tenant %(tenant_id)s") + + +class CredentialAlreadyExists(exceptions.QuantumException): + message = _("Credential %(credential_id)s already exists " \ + "for tenant %(tenant_id)s") + + class NexusPortBindingNotFound(exceptions.QuantumException): """NexusPort Binding is not present""" message = _("Nexus Port Binding %(port_id) is not present") diff --git a/quantum/plugins/cisco/db/l2network_db.py b/quantum/plugins/cisco/db/l2network_db.py index 6196fe17ea..4626fcd0d4 100644 --- a/quantum/plugins/cisco/db/l2network_db.py +++ b/quantum/plugins/cisco/db/l2network_db.py @@ -24,8 +24,8 @@ from quantum.plugins.cisco.common import cisco_exceptions as c_exc import l2network_models import logging as LOG import quantum.plugins.cisco.db.api as db -from quantum.plugins.cisco.db import nexus_db as ndb -from quantum.plugins.cisco.db import ucs_db as udb +import quantum.plugins.cisco.db.nexus_db as ndb +import quantum.plugins.cisco.db.ucs_db as udb def initialize(): @@ -132,6 +132,19 @@ def reserve_vlanid(): raise c_exc.VlanIDNotAvailable() +def get_all_vlanids_used(): + """Gets all the vlanids used""" + LOG.debug("get_all_vlanids() called") + session = db.get_session() + try: + vlanids = session.query(l2network_models.VlanID).\ + filter_by(vlan_used=True).\ + all() + return vlanids + except exc.NoResultFound: + return [] + + def get_all_vlan_bindings(): """Lists all the vlan to network associations""" LOG.debug("get_all_vlan_bindings() called") @@ -369,3 +382,162 @@ def update_pp_binding(tenantid, ppid, newtenantid=None, newportid=None, except exc.NoResultFound: raise c_exc.PortProfileNotFound(tenant_id=tenantid, portprofile_id=ppid) + + +def get_all_qoss(tenant_id): + """Lists all the qos to tenant associations""" + LOG.debug("get_all_qoss() called") + session = db.get_session() + try: + qoss = session.query(l2network_models.QoS).\ + filter_by(tenant_id=tenant_id).\ + all() + return qoss + except exc.NoResultFound: + return [] + + +def get_qos(tenant_id, qos_id): + """Lists the qos given a tenant_id and qos_id""" + LOG.debug("get_qos() called") + session = db.get_session() + try: + qos = session.query(l2network_models.QoS).\ + filter_by(tenant_id=tenant_id).\ + filter_by(uuid=qos_id).\ + one() + return qos + except exc.NoResultFound: + raise c_exc.QoSNotFound(qos_id=qos_id, + tenant_id=tenant_id) + + +def add_qos(tenant_id, qos_name, qos_desc): + """Adds a qos to tenant association""" + LOG.debug("add_qos() called") + session = db.get_session() + try: + qos = session.query(l2network_models.QoS).\ + filter_by(tenant_id=tenant_id).\ + filter_by(name=qos_name).\ + one() + raise c_exc.QosNameAlreadyExists(qos_name=qos_name, + tenant_id=tenant_id) + except exc.NoResultFound: + qos = l2network_models.QoS(tenant_id, qos_name, qos_desc) + session.add(qos) + session.flush() + return qos + + +def remove_qos(tenant_id, qos_id): + """Removes a qos to tenant association""" + session = db.get_session() + try: + qos = session.query(l2network_models.QoS).\ + filter_by(tenant_id=tenant_id).\ + filter_by(uuid=qos_id).\ + one() + session.delete(qos) + session.flush() + return qos + except exc.NoResultFound: + pass + + +def update_qos(tenant_id, qos_id, new_qos_name=None): + """Updates a qos to tenant association""" + session = db.get_session() + try: + qos = session.query(l2network_models.QoS).\ + filter_by(tenant_id=tenant_id).\ + filter_by(uuid=qos_id).\ + one() + if new_qos_name: + qos["name"] = new_qos_name + session.merge(qos) + session.flush() + return qos + except exc.NoResultFound: + raise c_exc.QoSNotFound(qos_id=qos_id, + tenant_id=tenant_id) + + +def get_all_credentials(tenant_id): + """Lists all the creds for a tenant""" + session = db.get_session() + try: + creds = session.query(l2network_models.Credential).\ + filter_by(tenant_id=tenant_id).\ + all() + return creds + except exc.NoResultFound: + return [] + + +def get_credential(tenant_id, credential_name): + """Lists the creds for given a cred_id and tenant_id""" + session = db.get_session() + try: + cred = session.query(l2network_models.Credential).\ + filter_by(tenant_id=tenant_id).\ + filter_by(name=credential_name).\ + one() + return cred + except exc.NoResultFound: + raise c_exc.CredentialNameNotFound(credential_name=credential_name, + tenant_id=tenant_id) + + +def add_credential(tenant_id, credential_name, user_name, password): + """Adds a qos to tenant association""" + session = db.get_session() + try: + cred = session.query(l2network_models.Credential).\ + filter_by(tenant_id=tenant_id).\ + filter_by(name=credential_name).\ + one() + raise c_exc.CredentialAlreadyExists(credential_name=credential_name, + tenant_id=tenant_id) + except exc.NoResultFound: + cred = l2network_models.Credential(tenant_id, + credential_name, user_name, password) + session.add(cred) + session.flush() + return cred + + +def remove_credential(tenant_id, credential_name): + """Removes a credential from a tenant""" + session = db.get_session() + try: + cred = session.query(l2network_models.Credential).\ + filter_by(tenant_id=tenant_id).\ + filter_by(name=credential_name).\ + one() + session.delete(cred) + session.flush() + return cred + except exc.NoResultFound: + pass + + +def update_credential(tenant_id, credential_name, + new_user_name=None, new_password=None): + """Updates a credential for a tenant""" + session = db.get_session() + try: + cred = session.query(l2network_models.Credential).\ + filter_by(tenant_id=tenant_id).\ + filter_by(name=credential_name).\ + one() + if new_user_name: + cred["user_name"] = new_user_name + if new_password: + cred["password"] = new_password + session.merge(cred) + session.flush() + return cred + except exc.NoResultFound: + raise c_exc.CredentialNameNotFound(credential_name=credential_name, + tenant_id=tenant_id) diff --git a/quantum/plugins/cisco/db/l2network_models.py b/quantum/plugins/cisco/db/l2network_models.py index 52039ff61f..bcfdd77680 100644 --- a/quantum/plugins/cisco/db/l2network_models.py +++ b/quantum/plugins/cisco/db/l2network_models.py @@ -145,3 +145,45 @@ class PortProfileBinding(BASE, L2NetworkBase): def __repr__(self): return "" % \ (self.tenant_id, self.port_id, self.portprofile_id, self.default) + + +class QoS(BASE, L2NetworkBase): + """Represents QoS for a tenant""" + __tablename__ = 'QoS' + + uuid = Column(String(255), primary_key=True) + tenant_id = Column(String(255)) + name = Column(String(255)) + desc = Column(String(255)) + + def __init__(self, tenant_id, qos_name, qos_desc): + self.uuid = uuid.uuid4() + self.tenant_id = tenant_id + self.name = qos_name + self.desc = qos_desc + + def __repr__(self): + return "" % \ + (self.tenant_id, self.name, self.desc) + + +class Credential(BASE, L2NetworkBase): + """Represents credentials for a tenant""" + __tablename__ = 'QoS' + + uuid = Column(String(255)) + tenant_id = Column(String(255), primary_key=True) + name = Column(String(255), primary_key=True) + user_name = Column(String(255)) + password = Column(String(255)) + + def __init__(self, tenant_id, name, user_name, password): + self.uuid = uuid.uuid4() + self.tenant_id = tenant_id + self.name = name + self.user_name = user_name + self.password = password + + def __repr__(self): + return "" % \ + (self.tenant_id, self.name, self.user_name, self.password) From 25560fd74e8466d51b4602203f10a03b53562792 Mon Sep 17 00:00:00 2001 From: rohitagarwalla Date: Wed, 24 Aug 2011 15:23:56 -0700 Subject: [PATCH 23/39] integration with l2network_plugin.py --- .../plugins/cisco/common/cisco_exceptions.py | 10 ++--- quantum/plugins/cisco/db/l2network_db.py | 28 +++++++------- quantum/plugins/cisco/db/l2network_models.py | 37 ++++++++++--------- quantum/plugins/cisco/db/ucs_db.py | 2 +- 4 files changed, 39 insertions(+), 38 deletions(-) diff --git a/quantum/plugins/cisco/common/cisco_exceptions.py b/quantum/plugins/cisco/common/cisco_exceptions.py index 0ef83528c5..02f4078daa 100644 --- a/quantum/plugins/cisco/common/cisco_exceptions.py +++ b/quantum/plugins/cisco/common/cisco_exceptions.py @@ -91,31 +91,31 @@ class VlanIDNotAvailable(exceptions.QuantumException): class QosNotFound(exceptions.QuantumException): + """QoS ID could not be found""" message = _("QoS level %(qos_id)s could not be found " \ "for tenant %(tenant_id)s") class QoSLevelInvalidDelete(exceptions.QuantumException): + """QoS ID could not be deleted""" message = _("QoS level %(qos_id)s could not be deleted " \ "for tenant %(tenant_id)s since association exists") class QosNameAlreadyExists(exceptions.QuantumException): + """QoS Name already exists""" message = _("QoS level with name %(qos_name)s already exists " \ "for tenant %(tenant_id)s") class CredentialNotFound(exceptions.QuantumException): + """Credential ID could not be found""" message = _("Credential %(credential_id)s could not be found " \ "for tenant %(tenant_id)s") -class CredentialNameNotFound(exceptions.QuantumException): - message = _("Credential %(credential_name)s could not be found " \ - "for tenant %(tenant_id)s") - - class CredentialAlreadyExists(exceptions.QuantumException): + """Credential ID already exists""" message = _("Credential %(credential_id)s already exists " \ "for tenant %(tenant_id)s") diff --git a/quantum/plugins/cisco/db/l2network_db.py b/quantum/plugins/cisco/db/l2network_db.py index 4626fcd0d4..b97ce5efab 100644 --- a/quantum/plugins/cisco/db/l2network_db.py +++ b/quantum/plugins/cisco/db/l2network_db.py @@ -404,7 +404,7 @@ def get_qos(tenant_id, qos_id): try: qos = session.query(l2network_models.QoS).\ filter_by(tenant_id=tenant_id).\ - filter_by(uuid=qos_id).\ + filter_by(qos_id=qos_id).\ one() return qos except exc.NoResultFound: @@ -419,7 +419,7 @@ def add_qos(tenant_id, qos_name, qos_desc): try: qos = session.query(l2network_models.QoS).\ filter_by(tenant_id=tenant_id).\ - filter_by(name=qos_name).\ + filter_by(qos_name=qos_name).\ one() raise c_exc.QosNameAlreadyExists(qos_name=qos_name, tenant_id=tenant_id) @@ -436,7 +436,7 @@ def remove_qos(tenant_id, qos_id): try: qos = session.query(l2network_models.QoS).\ filter_by(tenant_id=tenant_id).\ - filter_by(uuid=qos_id).\ + filter_by(qos_id=qos_id).\ one() session.delete(qos) session.flush() @@ -451,10 +451,10 @@ def update_qos(tenant_id, qos_id, new_qos_name=None): try: qos = session.query(l2network_models.QoS).\ filter_by(tenant_id=tenant_id).\ - filter_by(uuid=qos_id).\ + filter_by(qos_id=qos_id).\ one() if new_qos_name: - qos["name"] = new_qos_name + qos["qos_name"] = new_qos_name session.merge(qos) session.flush() return qos @@ -475,17 +475,17 @@ def get_all_credentials(tenant_id): return [] -def get_credential(tenant_id, credential_name): +def get_credential(tenant_id, credential_id): """Lists the creds for given a cred_id and tenant_id""" session = db.get_session() try: cred = session.query(l2network_models.Credential).\ filter_by(tenant_id=tenant_id).\ - filter_by(name=credential_name).\ + filter_by(credential_id=credential_id).\ one() return cred except exc.NoResultFound: - raise c_exc.CredentialNameNotFound(credential_name=credential_name, + raise c_exc.CredentialNotFound(credential_id=credential_id, tenant_id=tenant_id) @@ -495,7 +495,7 @@ def add_credential(tenant_id, credential_name, user_name, password): try: cred = session.query(l2network_models.Credential).\ filter_by(tenant_id=tenant_id).\ - filter_by(name=credential_name).\ + filter_by(credential_name=credential_name).\ one() raise c_exc.CredentialAlreadyExists(credential_name=credential_name, tenant_id=tenant_id) @@ -507,13 +507,13 @@ def add_credential(tenant_id, credential_name, user_name, password): return cred -def remove_credential(tenant_id, credential_name): +def remove_credential(tenant_id, credential_id): """Removes a credential from a tenant""" session = db.get_session() try: cred = session.query(l2network_models.Credential).\ filter_by(tenant_id=tenant_id).\ - filter_by(name=credential_name).\ + filter_by(credential_id=credential_id).\ one() session.delete(cred) session.flush() @@ -522,14 +522,14 @@ def remove_credential(tenant_id, credential_name): pass -def update_credential(tenant_id, credential_name, +def update_credential(tenant_id, credential_id, new_user_name=None, new_password=None): """Updates a credential for a tenant""" session = db.get_session() try: cred = session.query(l2network_models.Credential).\ filter_by(tenant_id=tenant_id).\ - filter_by(name=credential_name).\ + filter_by(credential_id=credential_id).\ one() if new_user_name: cred["user_name"] = new_user_name @@ -539,5 +539,5 @@ def update_credential(tenant_id, credential_name, session.flush() return cred except exc.NoResultFound: - raise c_exc.CredentialNameNotFound(credential_name=credential_name, + raise c_exc.CredentialNotFound(credential_id=credential_id, tenant_id=tenant_id) diff --git a/quantum/plugins/cisco/db/l2network_models.py b/quantum/plugins/cisco/db/l2network_models.py index bcfdd77680..53c0d3c7db 100644 --- a/quantum/plugins/cisco/db/l2network_models.py +++ b/quantum/plugins/cisco/db/l2network_models.py @@ -77,7 +77,7 @@ class VlanID(BASE, L2NetworkBase): self.vlan_used = False def __repr__(self): - return "" % \ + return "" % \ (self.vlan_id, self.vlan_used) @@ -149,41 +149,42 @@ class PortProfileBinding(BASE, L2NetworkBase): class QoS(BASE, L2NetworkBase): """Represents QoS for a tenant""" - __tablename__ = 'QoS' + __tablename__ = 'qoss' - uuid = Column(String(255), primary_key=True) - tenant_id = Column(String(255)) - name = Column(String(255)) - desc = Column(String(255)) + qos_id = Column(String(255)) + tenant_id = Column(String(255), primary_key=True) + qos_name = Column(String(255), primary_key=True) + qos_desc = Column(String(255)) def __init__(self, tenant_id, qos_name, qos_desc): - self.uuid = uuid.uuid4() + self.qos_id = uuid.uuid4() self.tenant_id = tenant_id - self.name = qos_name - self.desc = qos_desc + self.qos_name = qos_name + self.qos_desc = qos_desc def __repr__(self): - return "" % \ - (self.tenant_id, self.name, self.desc) + return "" % \ + (self.qos_id, self.tenant_id, self.qos_name, self.qos_desc) class Credential(BASE, L2NetworkBase): """Represents credentials for a tenant""" - __tablename__ = 'QoS' + __tablename__ = 'credentials' - uuid = Column(String(255)) + credential_id = Column(String(255)) tenant_id = Column(String(255), primary_key=True) - name = Column(String(255), primary_key=True) + credential_name = Column(String(255), primary_key=True) user_name = Column(String(255)) password = Column(String(255)) - def __init__(self, tenant_id, name, user_name, password): - self.uuid = uuid.uuid4() + def __init__(self, tenant_id, credential_name, user_name, password): + self.credential_id = uuid.uuid4() self.tenant_id = tenant_id - self.name = name + self.credential_name = credential_name self.user_name = user_name self.password = password def __repr__(self): return "" % \ - (self.tenant_id, self.name, self.user_name, self.password) + (self.credential_id, self.tenant_id, self.credential_name, + self.user_name, self.password) diff --git a/quantum/plugins/cisco/db/ucs_db.py b/quantum/plugins/cisco/db/ucs_db.py index 49ff512efd..14b09ad42e 100644 --- a/quantum/plugins/cisco/db/ucs_db.py +++ b/quantum/plugins/cisco/db/ucs_db.py @@ -20,9 +20,9 @@ import logging as LOG from sqlalchemy.orm import exc import quantum.plugins.cisco.db.api as db -import ucs_models from quantum.plugins.cisco.common import cisco_exceptions as c_exc +from quantum.plugins.cisco.db import ucs_models def get_all_ucsmbinding(): From 8b50cb07f6d67518a0495776ee50e645e271c88f Mon Sep 17 00:00:00 2001 From: rohitagarwalla Date: Wed, 24 Aug 2011 16:05:03 -0700 Subject: [PATCH 24/39] helper function to get creds based on name --- .../plugins/cisco/common/cisco_exceptions.py | 6 ++++++ quantum/plugins/cisco/db/l2network_db.py | 18 ++++++++++++++++-- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/quantum/plugins/cisco/common/cisco_exceptions.py b/quantum/plugins/cisco/common/cisco_exceptions.py index 02f4078daa..5e9eb77da6 100644 --- a/quantum/plugins/cisco/common/cisco_exceptions.py +++ b/quantum/plugins/cisco/common/cisco_exceptions.py @@ -114,6 +114,12 @@ class CredentialNotFound(exceptions.QuantumException): "for tenant %(tenant_id)s") +class CredentialNameNotFound(exceptions.QuantumException): + """Credential Name could not be found""" + message = _("Credential %(credential_name)s could not be found " \ + "for tenant %(tenant_id)s") + + class CredentialAlreadyExists(exceptions.QuantumException): """Credential ID already exists""" message = _("Credential %(credential_id)s already exists " \ diff --git a/quantum/plugins/cisco/db/l2network_db.py b/quantum/plugins/cisco/db/l2network_db.py index b97ce5efab..81557264ab 100644 --- a/quantum/plugins/cisco/db/l2network_db.py +++ b/quantum/plugins/cisco/db/l2network_db.py @@ -408,7 +408,7 @@ def get_qos(tenant_id, qos_id): one() return qos except exc.NoResultFound: - raise c_exc.QoSNotFound(qos_id=qos_id, + raise c_exc.QosNotFound(qos_id=qos_id, tenant_id=tenant_id) @@ -459,7 +459,7 @@ def update_qos(tenant_id, qos_id, new_qos_name=None): session.flush() return qos except exc.NoResultFound: - raise c_exc.QoSNotFound(qos_id=qos_id, + raise c_exc.QosNotFound(qos_id=qos_id, tenant_id=tenant_id) @@ -489,6 +489,20 @@ def get_credential(tenant_id, credential_id): tenant_id=tenant_id) +def get_credential_name(tenant_id, credential_name): + """Lists the creds for given a cred_name and tenant_id""" + session = db.get_session() + try: + cred = session.query(l2network_models.Credential).\ + filter_by(tenant_id=tenant_id).\ + filter_by(credential_name=credential_name).\ + one() + return cred + except exc.NoResultFound: + raise c_exc.CredentialNameNotFound(credential_name=credential_name, + tenant_id=tenant_id) + + def add_credential(tenant_id, credential_name, user_name, password): """Adds a qos to tenant association""" session = db.get_session() From 65440872ba3fb875fbb58ee8f5c7bf1dbd366f7a Mon Sep 17 00:00:00 2001 From: Sumit Naiksatam Date: Wed, 24 Aug 2011 16:53:08 -0700 Subject: [PATCH 25/39] Fixed some bugs with credential and qos resources; also fixed l2network_single_blade --- .../plugins/cisco/common/cisco_constants.py | 3 +- .../plugins/cisco/common/cisco_credentials.py | 47 ++++--- quantum/plugins/cisco/l2network_plugin.py | 116 ++++-------------- .../cisco/models/l2network_single_blade.py | 99 +++++++++------ 4 files changed, 119 insertions(+), 146 deletions(-) diff --git a/quantum/plugins/cisco/common/cisco_constants.py b/quantum/plugins/cisco/common/cisco_constants.py index edc3e2ea1f..fbcc9b94cc 100644 --- a/quantum/plugins/cisco/common/cisco_constants.py +++ b/quantum/plugins/cisco/common/cisco_constants.py @@ -148,5 +148,4 @@ LEAST_RSVD_BLADE_DICT = 'least_rsvd_blade_dict' UCSM_IP = 'ucsm_ip_address' -MAX_CREDENTIALS = 65568 -MAX_QOS_LEVELS = 1024 +NETWORK_ADMIN = 'network_admin' diff --git a/quantum/plugins/cisco/common/cisco_credentials.py b/quantum/plugins/cisco/common/cisco_credentials.py index f3c63065ce..d19e439283 100644 --- a/quantum/plugins/cisco/common/cisco_credentials.py +++ b/quantum/plugins/cisco/common/cisco_credentials.py @@ -24,10 +24,14 @@ import os from quantum.plugins.cisco.common import cisco_constants as const from quantum.plugins.cisco.common import cisco_configparser as confp +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" cp = confp.CiscoConfigParser(os.path.dirname(os.path.realpath(__file__)) \ @@ -39,32 +43,43 @@ class Store(object): """Credential Store""" @staticmethod - def putCredential(id, username, password): + def initialize(): + for id in _creds_dictionary.keys(): + try: + cdb.add_credential(TENANT, id, + _creds_dictionary[id][const.USERNAME], + _creds_dictionary[id][const.PASSWORD]) + except cexc.CredentialAlreadyExists: + # We are quietly ignoring this, since it only happens + # if this class module is loaded more than once, in which + # case, the credentials are already populated + pass + + @staticmethod + def putCredential(cred_name, username, password): """Set the username and password""" - _creds_dictionary[id] = {const.USERNAME: username, - const.PASSWORD: password} + credential = cdb.add_credential(TENANT, cred_name, username, password) @staticmethod - def getUsername(id): + def getUsername(cred_name): """Get the username""" - return _creds_dictionary[id][const.USERNAME] + credential = cdb.get_credential_name(TENANT, cred_name) + return credential[const.CREDENTIAL_USERNAME] @staticmethod - def getPassword(id): + def getPassword(cred_name): """Get the password""" - return _creds_dictionary[id][const.PASSWORD] + credential = cdb.get_credential_name(TENANT, cred_name) + return credential[const.CREDENTIAL_PASSWORD] @staticmethod - def getCredential(id): + def getCredential(cred_name): """Get the username and password""" - return _creds_dictionary[id] + credential = cdb.get_credential_name(TENANT, cred_name) + return {const.USERNAME: const.CREDENTIAL_USERNAME, + const.PASSWORD: const.CREDENTIAL_PASSWORD} @staticmethod - def getCredentials(): - """Get all usernames and passwords""" - return _creds_dictionary - - @staticmethod - def deleteCredential(id): + def deleteCredential(cred_name): """Delete a credential""" - return _creds_dictionary.pop(id) + cdb.remove_credential(TENANT, cred_name) diff --git a/quantum/plugins/cisco/l2network_plugin.py b/quantum/plugins/cisco/l2network_plugin.py index bdeedb521c..2a5ada6ff3 100644 --- a/quantum/plugins/cisco/l2network_plugin.py +++ b/quantum/plugins/cisco/l2network_plugin.py @@ -42,15 +42,12 @@ class L2Network(QuantumPluginBase): """ L2 Network Framework Plugin """ supported_extension_aliases = ["Cisco Credential", "Cisco Port Profile", "Cisco qos", "Cisco Nova Tenant"] - _qos_levels = {} - _credentials = {} def __init__(self): cdb.initialize() + cred.Store.initialize() self._model = utils.import_object(conf.MODEL_CLASS) self._vlan_mgr = utils.import_object(conf.MANAGER_CLASS) - self._qoslevels_counter = 0 - self._credentials_counter = 0 LOG.debug("L2Network plugin initialization done successfully\n") """ @@ -365,84 +362,60 @@ class L2Network(QuantumPluginBase): cdb.remove_pp_binding(tenant_id, port_id, portprofile_id) - def create_default_portprofile(self, tenant_id, network_id, profile_name, - qos): - "Create default port profile""" - LOG.debug("create_default_portprofile() called\n") - portprofile = cdb.add_portprofile(tenant_id, profile_name, - const.NO_VLAN_ID, qos) - new_pp = cutil.make_portprofile_dict(tenant_id, - portprofile[const.UUID], - portprofile[const.PPNAME], - portprofile[const.PPQOS]) - # TODO (Sumit): Need to check the following - port_id = None - cdb.add_pp_binding(tenant_id, port_id, portprofile[const.UUID], True) - return new_pp - def get_all_qoss(self, tenant_id): """Get all QoS levels""" LOG.debug("get_all_qoss() called\n") - return self._qos_levels.values() + qoslist = cdb.get_all_qoss(tenant_id) + return qoslist def get_qos_details(self, tenant_id, qos_id): """Get QoS Details""" LOG.debug("get_qos_details() called\n") try: - qos_level = self._get_qos_level(tenant_id, qos_id) + qos_level = cdb.get_qos(tenant_id, qos_id) except Exception, excp: raise cexc.QosNotFound(tenant_id=tenant_id, - qos_id=qos_id) + qos_id=qos_id) return qos_level def create_qos(self, tenant_id, qos_name, qos_desc): """Create a QoS level""" LOG.debug("create_qos() called\n") - qos_id = self._get_unique_qos_id(tenant_id) - new_qos_level_dict = {const.QOS_LEVEL_ID: qos_id, - const.QOS_LEVEL_NAME: qos_name, - const.QOS_LEVEL_ASSOCIATIONS: [], - const.QOS_LEVEL_DESCRIPTION: qos_desc} - self._qos_levels[qos_id] = new_qos_level_dict - return new_qos_level_dict + qos = cdb.add_qos(tenant_id, qos_name, qos_desc) + return qos def delete_qos(self, tenant_id, qos_id): """Delete a QoS level""" LOG.debug("delete_qos() called\n") try: - qos_level = self._get_qos_level(tenant_id, qos_id) + qos_level = cdb.get_qos(tenant_id, qos_id) except Exception, excp: raise cexc.QosNotFound(tenant_id=tenant_id, - qos_id=qos_id) - associations = qos_level[const.QOS_LEVEL_ASSOCIATIONS] - if len(associations) > 0: - raise cexc.QoSLevelInvalidDelete(tenant_id=tenant_id, - qos_id=qos_id) - else: - self._qos_levels.pop(qos_id) + qos_id=qos_id) + return cdb.remove_qos(tenant_id, qos_id) def rename_qos(self, tenant_id, qos_id, new_name): """Rename QoS level""" LOG.debug("rename_qos() called\n") - qos_level = self._get_qos_level(tenant_id, qos_id) try: - qos_level = self._get_qos_level(tenant_id, qos_id) + qos_level = cdb.get_qos(tenant_id, qos_id) except Exception, excp: raise cexc.QosNotFound(tenant_id=tenant_id, - qos_id=qos_id) - qos_level[const.QOS_LEVEL_NAME] = new_name - return qos_level + qos_id=qos_id) + qos = cdb.update_qos(tenant_id, qos_id, new_name) + return qos def get_all_credentials(self, tenant_id): """Get all credentials""" LOG.debug("get_all_credentials() called\n") - return self._credentials.values() + credential_list = cdb.get_all_credentials(tenant_id) + return credential_list def get_credential_details(self, tenant_id, credential_id): """Get a particular credential""" LOG.debug("get_credential_details() called\n") try: - credential = self._get_credential(tenant_id, credential_id) + credential = cdb.get_credential(tenant_id, credential_id) except Exception, excp: raise cexc.CredentialNotFound(tenant_id=tenant_id, credential_id=credential_id) @@ -452,37 +425,30 @@ class L2Network(QuantumPluginBase): password): """Create a new credential""" LOG.debug("create_credential() called\n") - credential_id = self._get_unique_credential_id(tenant_id) - masked_password = const.MASKED_PASSWORD - new_credential_dict = {const.CREDENTIAL_ID: credential_id, - const.CREDENTIAL_NAME: credential_name, - const.CREDENTIAL_USERNAME: user_name, - const.CREDENTIAL_PASSWORD: masked_password} - self._credentials[credential_id] = new_credential_dict - cred.Store.putCredential(credential_id, user_name, password) - return new_credential_dict + credential = cdb.add_credential(tenant_id, credential_name, + user_name, password) + return credential def delete_credential(self, tenant_id, credential_id): """Delete a credential""" LOG.debug("delete_credential() called\n") try: - credential = self._get_credential(tenant_id, credential_id) + credential = cdb.get_credential(tenant_id, credential_id) except Exception, excp: raise cexc.CredentialNotFound(tenant_id=tenant_id, credential_id=credential_id) - self._credentials.pop(credential_id) - cred.Store.deleteCredential(credential_id) + credential = cdb.remove_credential(tenant_id, credential_id) + return credential def rename_credential(self, tenant_id, credential_id, new_name): """Do nothing for this resource""" LOG.debug("rename_credential() called\n") try: - credential = self._get_credential(tenant_id, credential_id) + credential = cdb.get_credential(tenant_id, credential_id) except Exception, excp: raise cexc.CredentialNotFound(tenant_id=tenant_id, credential_id=credential_id) - - credential[const.CREDENTIAL_NAME] = new_name + credential = cdb.update_credential(tenant_id, credential_id, new_name) return credential def get_host(self, tenant_id, instance_id, instance_desc): @@ -533,35 +499,3 @@ class L2Network(QuantumPluginBase): def _func_name(self, offset=0): """Getting the name of the calling funciton""" return inspect.stack()[1 + offset][3] - - def _get_qos_level(self, tenant_id, qos_id): - """Return a QoS level based on the ID""" - qos_level = self._qos_levels.get(qos_id) - if not qos_level: - raise cexc.QosNotFound(tenant_id=tenant_id, - qos_id=qos_id) - return qos_level - - def _get_credential(self, tenant_id, credential_id): - """Return a credential based on the ID""" - credential = self._credentials.get(credential_id) - if not credential: - raise cexc.CredentialNotFound(tenant_id=tenant_id, - credetial_id=credential_id) - return credential - - def _get_unique_qos_id(self, tenant_id): - """Get a unique QoS ID""" - self._qoslevels_counter += 1 - self._qoslevels_counter %= int(const.MAX_QOS_LEVELS) - qos_id = tenant_id[16:] + "-qos-" + str(self._qoslevels_counter) - # TODO (Sumit): Need to check if the ID has already been allocated - return qos_id - - def _get_unique_credential_id(self, tenant_id): - """Get a unique credential ID""" - self._credentials_counter += 1 - self._credentials_counter %= int(const.MAX_CREDENTIALS) - cred_id = tenant_id[16:] + "-crd-" + str(self._credentials_counter) - # TODO (Sumit): Need to check if the ID has already been allocated - return cred_id diff --git a/quantum/plugins/cisco/models/l2network_single_blade.py b/quantum/plugins/cisco/models/l2network_single_blade.py index b4277af1a7..9cb0a89e03 100644 --- a/quantum/plugins/cisco/models/l2network_single_blade.py +++ b/quantum/plugins/cisco/models/l2network_single_blade.py @@ -19,26 +19,29 @@ # """ +from copy import deepcopy import inspect import logging as LOG import platform +from quantum.common import exceptions as exc from quantum.common import utils from quantum.plugins.cisco.l2network_model_base import L2NetworkModelBase 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(const.LOGGER_COMPONENT_NAME) +LOG.getLogger(__name__) -class L2NetworkSinlgeBlade(L2NetworkModelBase): +class L2NetworkSingleBlade(L2NetworkModelBase): """ Implements the L2NetworkModelBase - This implementation works with UCS and Nexus plugin, - with one UCS blade, and one Nexus switch. + This implementation works with a single UCS blade """ _plugins = {} + _inventory = {} def __init__(self): for key in conf.PLUGINS[const.PLUGINS].keys(): @@ -46,27 +49,50 @@ class L2NetworkSinlgeBlade(L2NetworkModelBase): conf.PLUGINS[const.PLUGINS][key]) LOG.debug("Loaded device plugin %s\n" % \ conf.PLUGINS[const.PLUGINS][key]) + if key in conf.PLUGINS[const.INVENTORY].keys(): + self._inventory[key] = utils.import_object( + conf.PLUGINS[const.INVENTORY][key]) + LOG.debug("Loaded device inventory %s\n" % \ + conf.PLUGINS[const.INVENTORY][key]) def _func_name(self, offset=0): """Get the name of the calling function""" return inspect.stack()[1 + offset][3] - def _invoke_all_device_plugins(self, function_name, args, kwargs): - """Invoke all device plugins for this model implementation""" - for plugin_obj_ref in self._plugins.values(): - getattr(plugin_obj_ref, function_name)(*args, **kwargs) + def _invoke_plugin_per_device(self, plugin_key, function_name, args): + """Invoke only device plugin for all the devices in the system""" + if not plugin_key in self._plugins.keys(): + LOG.info("No %s Plugin loaded" % plugin_key) + LOG.info("%s: %s with args %s ignored" \ + % (plugin_key, function_name, args)) + return + device_params = self._invoke_inventory(plugin_key, function_name, + args) + device_ips = device_params[const.DEVICE_IP] + if not device_ips: + self._invoke_plugin(plugin_key, function_name, args, + device_params) + else: + for device_ip in device_ips: + new_device_params = deepcopy(device_params) + new_device_params[const.DEVICE_IP] = device_ip + self._invoke_plugin(plugin_key, function_name, args, + new_device_params) - def _invoke_ucs_plugin(self, function_name, args, kwargs): - """Invoke only the UCS plugin""" - if const.UCS_PLUGIN in self._plugins.keys(): - getattr(self._plugins[const.UCS_PLUGIN], - function_name)(*args, **kwargs) + def _invoke_inventory(self, plugin_key, function_name, args): + """Invoke only the inventory implementation""" + if not plugin_key in self._inventory.keys(): + LOG.warn("No %s inventory loaded" % plugin_key) + LOG.warn("%s: %s with args %s ignored" \ + % (plugin_key, function_name, args)) + return {const.DEVICE_IP: []} + else: + return getattr(self._inventory[plugin_key], function_name)(args) - def _invoke_nexus_plugin(self, function_name, args, kwargs): - """Invoke only the Nexus plugin""" - if const.NEXUS_PLUGIN in self._plugins.keys(): - getattr(self._plugins[const.NEXUS_PLUGIN], - function_name)(*args, **kwargs) + def _invoke_plugin(self, plugin_key, function_name, args, kwargs): + """Invoke only the device plugin""" + return getattr(self._plugins[plugin_key], function_name)(*args, + **kwargs) def get_all_networks(self, args): """Not implemented for this model""" @@ -74,13 +100,13 @@ class L2NetworkSinlgeBlade(L2NetworkModelBase): def create_network(self, args): """Support for the Quantum core API call""" - device_params = {const.DEVICE_IP: ""} - self._invoke_all_device_plugins(self._func_name(), args, device_params) + self._invoke_plugin_per_device(const.UCS_PLUGIN, self._func_name(), + args) def delete_network(self, args): """Support for the Quantum core API call""" - device_params = {const.DEVICE_IP: ""} - self._invoke_all_device_plugins(self._func_name(), args, device_params) + self._invoke_plugin_per_device(const.UCS_PLUGIN, self._func_name(), + args) def get_network_details(self, args): """Not implemented for this model""" @@ -88,8 +114,8 @@ class L2NetworkSinlgeBlade(L2NetworkModelBase): def rename_network(self, args): """Support for the Quantum core API call""" - device_params = {const.DEVICE_IP: ""} - self._invoke_all_device_plugins(self._func_name(), args, device_params) + self._invoke_plugin_per_device(const.UCS_PLUGIN, self._func_name(), + args) def get_all_ports(self, args): """Not implemented for this model""" @@ -97,13 +123,13 @@ class L2NetworkSinlgeBlade(L2NetworkModelBase): def create_port(self, args): """Support for the Quantum core API call""" - device_params = {const.DEVICE_IP: ""} - self._invoke_ucs_plugin(self._func_name(), args, device_params) + self._invoke_plugin_per_device(const.UCS_PLUGIN, self._func_name(), + args) def delete_port(self, args): """Support for the Quantum core API call""" - device_params = {const.DEVICE_IP: ""} - self._invoke_ucs_plugin(self._func_name(), args, device_params) + self._invoke_plugin_per_device(const.UCS_PLUGIN, self._func_name(), + args) def update_port(self, args): """Not implemented for this model""" @@ -115,25 +141,24 @@ class L2NetworkSinlgeBlade(L2NetworkModelBase): def plug_interface(self, args): """Support for the Quantum core API call""" - device_params = {const.DEVICE_IP: ""} - self._invoke_ucs_plugin(self._func_name(), args, device_params) + self._invoke_plugin_per_device(const.UCS_PLUGIN, self._func_name(), + args) def unplug_interface(self, args): """Support for the Quantum core API call""" - device_params = {const.DEVICE_IP: ""} - self._invoke_ucs_plugin(self._func_name(), args, device_params) + self._invoke_plugin_per_device(const.UCS_PLUGIN, self._func_name(), + args) def get_host(self, args): """Provides the hostname on which a dynamic vnic is reserved""" LOG.debug("get_host() called\n") - host_list = {const.HOST_LIST: {const.HOST_1: platform.node()}} - return host_list + return self._invoke_inventory(const.UCS_PLUGIN, self._func_name(), + args) def get_instance_port(self, args): """ Get the portprofile name and the device namei for the dynamic vnic """ LOG.debug("get_instance_port() called\n") - vif_desc = {const.VIF_DESC: - {const.DEVICENAME: "eth2", const.UCSPROFILE: "default"}} - return vif_desc + return self._invoke_inventory(const.UCS_PLUGIN, self._func_name(), + args) From 727cc292bf5385153b6298445437587146961321 Mon Sep 17 00:00:00 2001 From: Edgar Magana Date: Thu, 25 Aug 2011 01:02:01 -0700 Subject: [PATCH 26/39] Configuration of multiple VLANs on the same Nexus Switch Interfaces --- .../cisco/nexus/cisco_nexus_network_driver.py | 25 ++++++++++++++++--- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/quantum/plugins/cisco/nexus/cisco_nexus_network_driver.py b/quantum/plugins/cisco/nexus/cisco_nexus_network_driver.py index f533c9f766..fce17dfb11 100644 --- a/quantum/plugins/cisco/nexus/cisco_nexus_network_driver.py +++ b/quantum/plugins/cisco/nexus/cisco_nexus_network_driver.py @@ -25,6 +25,7 @@ import logging as LOG from quantum.plugins.cisco.common import cisco_constants as const from quantum.plugins.cisco.nexus import cisco_nexus_snippets as snipp +from quantum.plugins.cisco.db import l2network_db as cdb from ncclient import manager @@ -112,8 +113,12 @@ class CiscoNEXUSDriver(): with self.nxos_connect(nexus_host, int(nexus_ssh_port), nexus_user, nexus_password) as man: self.enable_vlan(man, vlan_id, vlan_name) - self.enable_vlan_on_trunk_int(man, nexus_first_interface, vlan_id) - self.enable_vlan_on_trunk_int(man, nexus_second_interface, vlan_id) + vlan_ids = self.build_vlans_cmd() + LOG.debug("NexusDriver VLAN IDs: %s" % vlan_ids) + self.enable_vlan_on_trunk_int(man, nexus_first_interface, + vlan_ids) + self.enable_vlan_on_trunk_int(man, nexus_second_interface, + vlan_ids) def delete_vlan(self, vlan_id, nexus_host, nexus_user, nexus_password, nexus_first_interface, nexus_second_interface, @@ -125,5 +130,17 @@ class CiscoNEXUSDriver(): with self.nxos_connect(nexus_host, int(nexus_ssh_port), nexus_user, nexus_password) as man: self.disable_vlan(man, vlan_id) - self.disable_switch_port(man, nexus_first_interface) - self.disable_switch_port(man, nexus_second_interface) + self.disable_vlan_on_trunk_int(man, nexus_first_interface, + vlan_id) + self.disable_vlan_on_trunk_int(man, nexus_second_interface, + vlan_id) + + def build_vlans_cmd(self): + """ + Builds a string with all the VLANs on the same Switch + """ + assigned_vlan = cdb.get_all_vlanids_used() + vlans = '' + for vlanid in assigned_vlan: + vlans = str(vlanid["vlan_id"]) + ',' + vlans + return vlans.strip(',') From 51ddffa2641d0cf0725f7a5147ad0b90551e36a0 Mon Sep 17 00:00:00 2001 From: Edgar Magana Date: Thu, 25 Aug 2011 12:34:03 -0700 Subject: [PATCH 27/39] Fixed the Unit Test for Nexus Driver --- .../cisco/nexus/cisco_nexus_network_driver.py | 2 ++ .../cisco/tests/unit/test_nexus_plugin.py | 18 +++++++++++++++++- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/quantum/plugins/cisco/nexus/cisco_nexus_network_driver.py b/quantum/plugins/cisco/nexus/cisco_nexus_network_driver.py index fce17dfb11..717be135f9 100644 --- a/quantum/plugins/cisco/nexus/cisco_nexus_network_driver.py +++ b/quantum/plugins/cisco/nexus/cisco_nexus_network_driver.py @@ -143,4 +143,6 @@ class CiscoNEXUSDriver(): vlans = '' for vlanid in assigned_vlan: vlans = str(vlanid["vlan_id"]) + ',' + vlans + if vlans == '': + vlans = 'none' return vlans.strip(',') diff --git a/quantum/plugins/cisco/tests/unit/test_nexus_plugin.py b/quantum/plugins/cisco/tests/unit/test_nexus_plugin.py index e9f95f1fca..bfb7b851bf 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.nexus import cisco_nexus_plugin from quantum.plugins.cisco.db import l2network_db as cdb +from quantum.plugins.cisco.db import api as db LOG = logging.getLogger('quantum.tests.test_nexus') @@ -34,8 +35,8 @@ class TestNexusPlugin(unittest.TestCase): self.vlan_name = "q-" + str(self.net_id) + "vlan" self.vlan_id = 267 self.port_id = "9" - self._cisco_nexus_plugin = cisco_nexus_plugin.NexusPlugin() cdb.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, @@ -66,6 +67,8 @@ class TestNexusPlugin(unittest.TestCase): else: vlan_id = self.vlan_id + network_created = self.create_network(tenant_id, net_id) + 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) @@ -260,6 +263,19 @@ class TestNexusPlugin(unittest.TestCase): self.tearDownNetwork(tenant_id, new_net_dict[const.NET_ID]) LOG.debug("test_get_vlan_id_for_network - END") + def create_network(self, tenant_id, net_name): + """Create a network""" + net_dict = {} + try: + res = db.network_create(tenant_id, net_name) + LOG.debug("Created network: %s" % res.uuid) + net_dict["tenant-id"] = res.tenant_id + net_dict["net-id"] = str(res.uuid) + net_dict["net-name"] = res.name + return net_dict + except Exception, exc: + LOG.error("Failed to create network: %s" % str(exc)) + def tearDownNetwork(self, tenant_id, network_dict_id): """ Clean up functions after the tests From 7d7ac483cf323c00c522fa465fd1df0f05fb3317 Mon Sep 17 00:00:00 2001 From: Edgar Magana Date: Thu, 25 Aug 2011 12:50:02 -0700 Subject: [PATCH 28/39] Sorting correctly all imports for the Nexus Driver and Unit Test --- quantum/plugins/cisco/nexus/cisco_nexus_network_driver.py | 2 +- quantum/plugins/cisco/nexus/cisco_nexus_plugin.py | 2 +- quantum/plugins/cisco/tests/unit/test_nexus_plugin.py | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/quantum/plugins/cisco/nexus/cisco_nexus_network_driver.py b/quantum/plugins/cisco/nexus/cisco_nexus_network_driver.py index 717be135f9..06b6ad30ee 100644 --- a/quantum/plugins/cisco/nexus/cisco_nexus_network_driver.py +++ b/quantum/plugins/cisco/nexus/cisco_nexus_network_driver.py @@ -24,8 +24,8 @@ Implements a Nexus-OS NETCONF over SSHv2 API Client import logging as LOG from quantum.plugins.cisco.common import cisco_constants as const -from quantum.plugins.cisco.nexus import cisco_nexus_snippets as snipp from quantum.plugins.cisco.db import l2network_db as cdb +from quantum.plugins.cisco.nexus import cisco_nexus_snippets as snipp from ncclient import manager diff --git a/quantum/plugins/cisco/nexus/cisco_nexus_plugin.py b/quantum/plugins/cisco/nexus/cisco_nexus_plugin.py index 62f3806f32..dd93cf10e3 100644 --- a/quantum/plugins/cisco/nexus/cisco_nexus_plugin.py +++ b/quantum/plugins/cisco/nexus/cisco_nexus_plugin.py @@ -26,9 +26,9 @@ 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 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 -from quantum.plugins.cisco.db import nexus_db as nxos_db LOG.basicConfig(level=LOG.WARN) LOG.getLogger(const.LOGGER_COMPONENT_NAME) diff --git a/quantum/plugins/cisco/tests/unit/test_nexus_plugin.py b/quantum/plugins/cisco/tests/unit/test_nexus_plugin.py index bfb7b851bf..f95352eef0 100644 --- a/quantum/plugins/cisco/tests/unit/test_nexus_plugin.py +++ b/quantum/plugins/cisco/tests/unit/test_nexus_plugin.py @@ -14,13 +14,13 @@ # # @author: Shweta Padubidri, Peter Strunk, Cisco Systems, Inc. # -import unittest import logging +import unittest from quantum.common import exceptions as exc from quantum.plugins.cisco.common import cisco_constants as const -from quantum.plugins.cisco.nexus import cisco_nexus_plugin from quantum.plugins.cisco.db import l2network_db as cdb from quantum.plugins.cisco.db import api as db +from quantum.plugins.cisco.nexus import cisco_nexus_plugin LOG = logging.getLogger('quantum.tests.test_nexus') From b454982d0e0bc9e07343f07db1f787de2469045c Mon Sep 17 00:00:00 2001 From: rohitagarwalla Date: Thu, 25 Aug 2011 16:29:30 -0700 Subject: [PATCH 29/39] Cleaning (removing) unused code..hooray ! fixes for extension tests --- quantum/plugins/cisco/db/l2network_models.py | 4 +- quantum/plugins/cisco/db/ucs_db.py | 256 ---------- quantum/plugins/cisco/db/ucs_models.py | 83 +--- .../plugins/cisco/tests/unit/test_database.py | 467 +----------------- 4 files changed, 10 insertions(+), 800 deletions(-) diff --git a/quantum/plugins/cisco/db/l2network_models.py b/quantum/plugins/cisco/db/l2network_models.py index 53c0d3c7db..8051de5849 100644 --- a/quantum/plugins/cisco/db/l2network_models.py +++ b/quantum/plugins/cisco/db/l2network_models.py @@ -157,7 +157,7 @@ class QoS(BASE, L2NetworkBase): qos_desc = Column(String(255)) def __init__(self, tenant_id, qos_name, qos_desc): - self.qos_id = uuid.uuid4() + self.qos_id = str(uuid.uuid4()) self.tenant_id = tenant_id self.qos_name = qos_name self.qos_desc = qos_desc @@ -178,7 +178,7 @@ class Credential(BASE, L2NetworkBase): password = Column(String(255)) def __init__(self, tenant_id, credential_name, user_name, password): - self.credential_id = uuid.uuid4() + self.credential_id = str(uuid.uuid4()) self.tenant_id = tenant_id self.credential_name = credential_name self.user_name = user_name diff --git a/quantum/plugins/cisco/db/ucs_db.py b/quantum/plugins/cisco/db/ucs_db.py index 14b09ad42e..cfe2df27ec 100644 --- a/quantum/plugins/cisco/db/ucs_db.py +++ b/quantum/plugins/cisco/db/ucs_db.py @@ -25,262 +25,6 @@ from quantum.plugins.cisco.common import cisco_exceptions as c_exc from quantum.plugins.cisco.db import ucs_models -def get_all_ucsmbinding(): - """Lists all the ucsm bindings""" - LOG.debug("get_all_ucsmbinding() called") - session = db.get_session() - try: - bindings = session.query(ucs_models.UcsmBinding).\ - all() - return bindings - except exc.NoResultFound: - return [] - - -def get_ucsmbinding(ucsm_ip): - """Lists a ucsm binding""" - LOG.debug("get_ucsmbinding() called") - session = db.get_session() - try: - binding = session.query(ucs_models.UcsmBinding).\ - filter_by(ucsm_ip=ucsm_ip).\ - one() - return binding - except exc.NoResultFound: - raise c_exc.UcsmBindingNotFound(ucsm_ip=ucsm_ip) - - -def add_ucsmbinding(ucsm_ip, network_id): - """Adds a ucsm binding""" - LOG.debug("add_ucsmbinding() called") - session = db.get_session() - try: - binding = session.query(ucs_models.UcsmBinding).\ - filter_by(ucsm_ip=ucsm_ip).\ - one() - raise c_exc.UcsmBindingAlreadyExists(ucsm_ip=ucsm_ip) - except exc.NoResultFound: - binding = ucs_models.UcsmBinding(ucsm_ip, network_id) - session.add(binding) - session.flush() - return binding - - -def remove_ucsmbinding(ucsm_ip): - """Removes a ucsm binding""" - LOG.debug("remove_ucsmbinding() called") - session = db.get_session() - try: - binding = session.query(ucs_models.UcsmBinding).\ - filter_by(ucsm_ip=ucsm_ip).\ - one() - session.delete(binding) - session.flush() - return binding - except exc.NoResultFound: - pass - - -def update_ucsmbinding(ucsm_ip, new_network_id): - """Updates ucsm binding""" - LOG.debug("update_ucsmbinding() called") - session = db.get_session() - try: - binding = session.query(ucs_models.UcsmBinding).\ - filter_by(ucsm_ip=ucsm_ip).\ - one() - if new_network_id: - binding.network_id = new_network_id - session.merge(binding) - session.flush() - return binding - except exc.NoResultFound: - raise c_exc.UcsmBindingNotFound(ucsm_ip=ucsm_ip) - - -def get_all_dynamicvnics(): - """Lists all the dynamic vnics""" - LOG.debug("get_all_dynamicvnics() called") - session = db.get_session() - try: - vnics = session.query(ucs_models.DynamicVnic).\ - all() - return vnics - except exc.NoResultFound: - return [] - - -def get_dynamicvnic(vnic_id): - """Lists a dynamic vnic""" - LOG.debug("get_dynamicvnic() called") - session = db.get_session() - try: - vnic = session.query(ucs_models.DynamicVnic).\ - filter_by(uuid=vnic_id).\ - one() - return vnic - except exc.NoResultFound: - raise c_exc.DynamicVnicNotFound(vnic_id=vnic_id) - - -def add_dynamicvnic(device_name, blade_id, vnic_state): - """Adds a dynamic vnic""" - LOG.debug("add_dynamicvnic() called") - session = db.get_session() - try: - vnic = session.query(ucs_models.DynamicVnic).\ - filter_by(device_name=device_name).\ - one() - raise c_exc.DynamicVnicAlreadyExists(device_name=device_name) - except exc.NoResultFound: - vnic = ucs_models.DynamicVnic(device_name, blade_id, vnic_state) - session.add(vnic) - session.flush() - return vnic - - -def remove_dynamicvnic(vnic_id): - """Removes a dynamic vnic""" - LOG.debug("remove_dynamicvnic() called") - session = db.get_session() - try: - vnic = session.query(ucs_models.DynamicVnic).\ - filter_by(uuid=vnic_id).\ - one() - session.delete(vnic) - session.flush() - return vnic - except exc.NoResultFound: - pass - - -def update_dynamicvnic(vnic_id, new_device_name=None, new_blade_id=None, - vnic_state=None, blade_intf_dn=None, - blade_intf_order=None, blade_int_link_state=None, - blade_intf_oper_state=None, blade_intf_inst_type=None, - blade_intf_reservation=None): - """Updates dynamic vnic""" - LOG.debug("update_dynamicvnic() called") - session = db.get_session() - try: - vnic = session.query(ucs_models.DynamicVnic).\ - filter_by(uuid=vnic_id).\ - one() - if new_device_name: - vnic.device_name = new_device_name - if new_blade_id: - vnic.blade_id = new_blade_id - if vnic_state: - vnic.vnic_state = vnic_state - if blade_intf_dn: - vnic.blade_intf_dn = blade_intf_dn - if blade_intf_order: - vnic.blade_intf_order = blade_intf_order - if blade_int_link_state: - vnic.blade_int_link_state = blade_int_link_state - if blade_intf_oper_state: - vnic.blade_intf_oper_state = blade_intf_oper_state - if blade_intf_inst_type: - vnic.blade_intf_inst_type = blade_intf_inst_type - if blade_intf_reservation: - vnic.blade_intf_reservation = blade_intf_reservation - session.merge(vnic) - session.flush() - return vnic - except exc.NoResultFound: - raise c_exc.DynamicVnicNotFound(vnic_id=vnic_id) - - -def get_all_blades(): - """Lists all the blades details""" - LOG.debug("get_all_blades() called") - session = db.get_session() - try: - blades = session.query(ucs_models.UcsBlade).\ - all() - return blades - except exc.NoResultFound: - return [] - - -def get_blade(blade_id): - """Lists a blade details""" - LOG.debug("get_blade() called") - session = db.get_session() - try: - blade = session.query(ucs_models.UcsBlade).\ - filter_by(uuid=blade_id).\ - one() - return blade - except exc.NoResultFound: - raise c_exc.BladeNotFound(blade_id=blade_id) - - -def add_blade(mgmt_ip, mac_addr, chassis_id, ucsm_ip, blade_state, - vnics_used, hostname): - """Adds a blade""" - LOG.debug("add_blade() called") - session = db.get_session() - try: - blade = session.query(ucs_models.UcsBlade).\ - filter_by(mgmt_ip=mgmt_ip).\ - one() - raise c_exc.BladeAlreadyExists(mgmt_ip=mgmt_ip) - except exc.NoResultFound: - blade = ucs_models.UcsBlade(mgmt_ip, mac_addr, chassis_id, ucsm_ip, - blade_state, vnics_used, hostname) - session.add(blade) - session.flush() - return blade - - -def remove_blade(blade_id): - """Removes a blade""" - LOG.debug("remove_blade() called") - session = db.get_session() - try: - blade = session.query(ucs_models.UcsBlade).\ - filter_by(uuid=blade_id).\ - one() - session.delete(blade) - session.flush() - return blade - except exc.NoResultFound: - pass - - -def update_blade(blade_id, new_mgmt_ip=None, new_mac_addr=None, - new_chassis_id=None, new_ucsm_ip=None, - new_blade_state=None, new_vnics_used=None, - new_hostname=None): - """Updates details of a blade""" - LOG.debug("update_blade() called") - session = db.get_session() - try: - blade = session.query(ucs_models.UcsBlade).\ - filter_by(uuid=blade_id).\ - one() - if new_mgmt_ip: - blade.mgmt_ip = new_mgmt_ip - if new_mac_addr: - blade.mac_addr = new_mac_addr - if new_chassis_id: - blade.chassis_id = new_chassis_id - if new_ucsm_ip: - blade.ucsm_ip = new_ucsm_ip - if new_blade_state: - blade.blade_state = new_blade_state - if new_vnics_used: - blade.vnics_used = new_vnics_used - if new_hostname: - blade.hostname = new_hostname - session.merge(blade) - session.flush() - return blade - except exc.NoResultFound: - raise c_exc.BladeNotFound(blade_id=blade_id) - - def get_all_portbindings(): """Lists all the port bindings""" LOG.debug("db get_all_portbindings() called") diff --git a/quantum/plugins/cisco/db/ucs_models.py b/quantum/plugins/cisco/db/ucs_models.py index be7c18aab9..b799bb244f 100644 --- a/quantum/plugins/cisco/db/ucs_models.py +++ b/quantum/plugins/cisco/db/ucs_models.py @@ -15,95 +15,14 @@ # under the License. # @author: Rohit Agarwalla, Cisco Systems, Inc. -import uuid - from sqlalchemy import Column, Integer, String, ForeignKey from sqlalchemy.orm import relation -from quantum.plugins.cisco.db.l2network_models import L2NetworkBase from quantum.plugins.cisco.db import models +from quantum.plugins.cisco.db.l2network_models import L2NetworkBase from quantum.plugins.cisco.db.models import BASE -class UcsmBinding(BASE, L2NetworkBase): - """Represents a binding of ucsm to network_id""" - __tablename__ = 'ucsm_bindings' - - id = Column(Integer, primary_key=True, autoincrement=True) - ucsm_ip = Column(String(255)) - network_id = Column(String(255), ForeignKey("networks.uuid"), - nullable=False) - network = relation(models.Network) - - def __init__(self, ucsm_ip, network_id): - self.ucsm_ip = ucsm_ip - self.network_id = network_id - - def __repr__(self): - return "" % \ - (self.ucsm_ip, self.network_id) - - -class DynamicVnic(BASE, L2NetworkBase): - """Represents Cisco UCS Dynamic Vnics""" - __tablename__ = 'dynamic_vnics' - - uuid = Column(String(255), primary_key=True) - device_name = Column(String(255)) - blade_id = Column(String(255), ForeignKey("ucs_blades.uuid"), - nullable=False) - vnic_state = Column(String(255)) - blade_intf_dn = Column(String(255)) - blade_intf_order = Column(String(255)) - blade_int_link_state = Column(String(255)) - blade_intf_oper_state = Column(String(255)) - blade_intf_inst_type = Column(String(255)) - blade_intf_reservation = Column(String(255)) - - def __init__(self, device_name, blade_id, vnic_state): - self.uuid = uuid.uuid4() - self.device_name = device_name - self.blade_id = blade_id - self.vnic_state = vnic_state - - def __repr__(self): - return "" % \ - (self.uuid, self.device_name, self.blade_id, - self.vnic_state) - - -class UcsBlade(BASE, L2NetworkBase): - """Represents details of ucs blades""" - __tablename__ = 'ucs_blades' - - uuid = Column(String(255), primary_key=True) - mgmt_ip = Column(String(255)) - mac_addr = Column(String(255)) - chassis_id = Column(String(255)) - ucsm_ip = Column(String(255)) - blade_state = Column(String(255)) - vnics_used = Column(Integer) - hostname = Column(String(255)) - dynamic_vnics = relation(DynamicVnic, order_by=DynamicVnic.uuid, - backref="blade") - - def __init__(self, mgmt_ip, mac_addr, chassis_id, ucsm_ip, - blade_state, vnics_used, hostname): - self.uuid = uuid.uuid4() - self.mgmt_ip = mgmt_ip - self.mac_addr = mac_addr - self.chassis_id = chassis_id - self.ucsm_ip = ucsm_ip - self.blade_state = blade_state - self.vnics_used = vnics_used - self.hostname = hostname - - def __repr__(self): - return "" % \ - (self.uuid, self.mgmt_ip, self.mac_addr, self.chassis_id, - self.ucsm_ip, self.blade_state, self.vnics_used, self.hostname) - - class PortBinding(BASE, L2NetworkBase): """Represents Port binding to device interface""" __tablename__ = 'port_bindings' diff --git a/quantum/plugins/cisco/tests/unit/test_database.py b/quantum/plugins/cisco/tests/unit/test_database.py index 8e3b7b6b8c..4a5ffc9d66 100644 --- a/quantum/plugins/cisco/tests/unit/test_database.py +++ b/quantum/plugins/cisco/tests/unit/test_database.py @@ -35,235 +35,6 @@ LOG.getLogger(const.LOGGER_COMPONENT_NAME) class UcsDB(object): """Class consisting of methods to call ucs db methods""" - def get_all_ucsmbindings(self): - """get all ucsm bindings""" - bindings = [] - try: - for res in ucs_db.get_all_ucsmbinding(): - LOG.debug("Getting ucsm binding : %s" % res.ucsm_ip) - bind_dict = {} - bind_dict["ucsm-ip"] = str(res.ucsm_ip) - bind_dict["network-id"] = str(res.network_id) - bindings.append(bind_dict) - except Exception, exc: - LOG.error("Failed to get all bindings: %s" % str(exc)) - return bindings - - def get_ucsmbinding(self, ucsm_ip): - """get ucsm binding""" - binding = [] - try: - for res in ucs_db.get_ucsmbinding(ucsm_ip): - LOG.debug("Getting ucsm binding : %s" % res.ucsm_ip) - bind_dict = {} - bind_dict["ucsm-ip"] = str(res.ucsm_ip) - bind_dict["network-id"] = str(res.network_id) - binding.append(bind_dict) - except Exception, exc: - LOG.error("Failed to get binding: %s" % str(exc)) - return binding - - def create_ucsmbinding(self, ucsm_ip, network_id): - """create ucsm binding""" - bind_dict = {} - try: - res = ucs_db.add_ucsmbinding(ucsm_ip, network_id) - LOG.debug("Created ucsm binding: %s" % res.ucsm_ip) - bind_dict["ucsm-ip"] = str(res.ucsm_ip) - bind_dict["network-id"] = str(res.network_id) - return bind_dict - except Exception, exc: - LOG.error("Failed to create ucsm binding: %s" % str(exc)) - - def delete_ucsmbinding(self, ucsm_ip): - """delete ucsm binding""" - try: - res = ucs_db.remove_ucsmbinding(ucsm_ip) - LOG.debug("Deleted ucsm binding : %s" % res.ucsm_ip) - bind_dict = {} - bind_dict["ucsm-ip"] = str(res.ucsm_ip) - return bind_dict - except Exception, exc: - raise Exception("Failed to delete dynamic vnic: %s" % str(exc)) - - def update_ucsmbinding(self, ucsm_ip, network_id): - """update ucsm binding""" - try: - res = ucs_db.update_ucsmbinding(ucsm_ip, network_id) - LOG.debug("Updating ucsm binding : %s" % res.ucsm_ip) - bind_dict = {} - bind_dict["ucsm-ip"] = str(res.ucsm_ip) - bind_dict["network-id"] = str(res.network_id) - return bind_dict - except Exception, exc: - raise Exception("Failed to update dynamic vnic: %s" % str(exc)) - - def get_all_dynamicvnics(self): - """get all dynamic vnics""" - vnics = [] - try: - for res in ucs_db.get_all_dynamicvnics(): - LOG.debug("Getting dynamic vnic : %s" % res.uuid) - vnic_dict = {} - vnic_dict["vnic-id"] = str(res.uuid) - vnic_dict["device-name"] = res.device_name - vnic_dict["blade-id"] = str(res.blade_id) - vnic_dict["vnic_state"] = res.vnic_state - vnics.append(vnic_dict) - except Exception, exc: - LOG.error("Failed to get all dynamic vnics: %s" % str(exc)) - return vnics - - def get_dynamicvnic(self, vnic_id): - """get dynamic vnic""" - vnic = [] - try: - for res in ucs_db.get_dynamicvnic(vnic_id): - LOG.debug("Getting dynamic vnic : %s" % res.uuid) - vnic_dict = {} - vnic_dict["vnic-id"] = str(res.uuid) - vnic_dict["device-name"] = res.device_name - vnic_dict["blade-id"] = str(res.blade_id) - vnic_dict["vnic_state"] = res.vnic_state - vnic.append(vnic_dict) - except Exception, exc: - LOG.error("Failed to get dynamic vnic: %s" % str(exc)) - return vnic - - def create_dynamicvnic(self, device_name, blade_id, vnic_state): - """create dynamic vnic""" - vnic_dict = {} - try: - res = ucs_db.add_dynamicvnic(device_name, blade_id, vnic_state) - LOG.debug("Created dynamic vnic: %s" % res.uuid) - vnic_dict["vnic-id"] = str(res.uuid) - vnic_dict["device-name"] = res.device_name - vnic_dict["blade-id"] = str(res.blade_id) - vnic_dict["vnic_state"] = res.vnic_state - return vnic_dict - except Exception, exc: - LOG.error("Failed to create dynamic vnic: %s" % str(exc)) - - def delete_dynamicvnic(self, vnic_id): - """delete dynamic vnic""" - try: - res = ucs_db.remove_dynamicvnic(vnic_id) - LOG.debug("Deleted dynamic vnic : %s" % res.uuid) - vnic_dict = {} - vnic_dict["vnic-id"] = str(res.uuid) - return vnic_dict - except Exception, exc: - raise Exception("Failed to delete dynamic vnic: %s" % str(exc)) - - def update_dynamicvnic(self, vnic_id, device_name=None, blade_id=None, - vnic_state=None): - """update dynamic vnic""" - try: - res = ucs_db.update_dynamicvnic(vnic_id, device_name, blade_id, - vnic_state) - LOG.debug("Updating dynamic vnic : %s" % res.uuid) - vnic_dict = {} - vnic_dict["vnic-id"] = str(res.uuid) - vnic_dict["device-name"] = res.device_name - vnic_dict["blade-id"] = str(res.blade_id) - vnic_dict["vnic_state"] = res.vnic_state - return vnic_dict - except Exception, exc: - raise Exception("Failed to update dynamic vnic: %s" % str(exc)) - - def get_all_blades(self): - """get all blades""" - blades = [] - try: - for res in ucs_db.get_all_blades(): - LOG.debug("Getting blade : %s" % res.uuid) - blade_dict = {} - blade_dict["blade-id"] = str(res.uuid) - blade_dict["mgmt-ip"] = str(res.mgmt_ip) - blade_dict["mac-addr"] = str(res.mac_addr) - blade_dict["chassis-id"] = str(res.chassis_id) - blade_dict["ucsm-ip"] = str(res.ucsm_ip) - blade_dict["blade_state"] = str(res.blade_state) - blade_dict["vnics_used"] = str(res.vnics_used) - blade_dict["hostname"] = str(res.hostname) - blades.append(blade_dict) - except Exception, exc: - LOG.error("Failed to get all blades: %s" % str(exc)) - return blades - - def get_blade(self, blade_id): - """get blade""" - blade = [] - try: - for res in ucs_db.get_blade(blade_id): - LOG.debug("Getting blade : %s" % res.uuid) - blade_dict = {} - blade_dict["blade-id"] = str(res.uuid) - blade_dict["mgmt-ip"] = str(res.mgmt_ip) - blade_dict["mac-addr"] = str(res.mac_addr) - blade_dict["chassis-id"] = str(res.chassis_id) - blade_dict["ucsm-ip"] = str(res.ucsm_ip) - blade_dict["blade_state"] = str(res.blade_state) - blade_dict["vnics_used"] = str(res.vnics_used) - blade_dict["hostname"] = str(res.hostname) - blade.append(blade_dict) - except Exception, exc: - LOG.error("Failed to get all blades: %s" % str(exc)) - return blade - - def create_blade(self, mgmt_ip, mac_addr, chassis_id, ucsm_ip, - blade_state, vnics_used, hostname): - """create blade""" - blade_dict = {} - try: - res = ucs_db.add_blade(mgmt_ip, mac_addr, chassis_id, ucsm_ip, - blade_state, vnics_used, hostname) - LOG.debug("Created blade: %s" % res.uuid) - blade_dict["blade-id"] = str(res.uuid) - blade_dict["mgmt-ip"] = str(res.mgmt_ip) - blade_dict["mac-addr"] = str(res.mac_addr) - blade_dict["chassis-id"] = str(res.chassis_id) - blade_dict["ucsm-ip"] = str(res.ucsm_ip) - blade_dict["blade_state"] = str(res.blade_state) - blade_dict["vnics_used"] = str(res.vnics_used) - blade_dict["hostname"] = str(res.hostname) - return blade_dict - except Exception, exc: - LOG.error("Failed to create blade: %s" % str(exc)) - - def delete_blade(self, blade_id): - """delete blade""" - try: - res = ucs_db.remove_blade(blade_id) - LOG.debug("Deleted blade : %s" % res.uuid) - blade_dict = {} - blade_dict["blade-id"] = str(res.uuid) - return blade_dict - except Exception, exc: - raise Exception("Failed to delete blade: %s" % str(exc)) - - def update_blade(self, blade_id, mgmt_ip=None, mac_addr=None, - chassis_id=None, ucsm_ip=None, blade_state=None, - vnics_used=None, hostname=None): - """update blade""" - try: - res = ucs_db.update_blade(blade_id, mgmt_ip, mac_addr, - chassis_id, ucsm_ip, blade_state, - vnics_used, hostname) - LOG.debug("Updating blade : %s" % res.uuid) - blade_dict = {} - blade_dict["blade-id"] = str(res.uuid) - blade_dict["mgmt-ip"] = str(res.mgmt_ip) - blade_dict["mac-addr"] = str(res.mac_addr) - blade_dict["chassis-id"] = str(res.chassis_id) - blade_dict["ucsm-ip"] = str(res.ucsm_ip) - blade_dict["blade_state"] = str(res.blade_state) - blade_dict["vnics_used"] = str(res.vnics_used) - blade_dict["hostname"] = str(res.hostname) - return blade_dict - except Exception, exc: - raise Exception("Failed to update blade: %s" % str(exc)) - def get_all_port_bindings(self): """get all port binding""" port_bindings = [] @@ -824,177 +595,14 @@ class UcsDBTest(unittest.TestCase): """Tear Down""" db.clear_db() - def testa_create_ucsmbinding(self): - """create ucsm binding""" - net1 = self.quantum.create_network("t1", "netid1") - binding1 = self.dbtest.create_ucsmbinding("1.2.3.4", net1["net-id"]) - self.assertTrue(binding1["ucsm-ip"] == "1.2.3.4") - self.teardown_ucsmbinding() - self.teardown_network() - - def testb_getall_ucsmbindings(self): - """get all ucsm bindings""" - net1 = self.quantum.create_network("t1", "netid1") - binding1 = self.dbtest.create_ucsmbinding("1.2.3.4", net1["net-id"]) - binding2 = self.dbtest.create_ucsmbinding("2.3.4.5", net1["net-id"]) - bindings = self.dbtest.get_all_ucsmbindings() - count = 0 - for bind in bindings: - if net1["net-id"] == bind["network-id"]: - count += 1 - self.assertTrue(count == 2) - self.teardown_ucsmbinding() - self.teardown_network() - - def testc_delete_ucsmbinding(self): - """delete ucsm binding""" - net1 = self.quantum.create_network("t1", "netid1") - binding1 = self.dbtest.create_ucsmbinding("1.2.3.4", net1["net-id"]) - self.dbtest.delete_ucsmbinding(binding1["ucsm-ip"]) - bindings = self.dbtest.get_all_ucsmbindings() - count = 0 - for bind in bindings: - if "net " in bind["network-id"]: - count += 1 - self.assertTrue(count == 0) - self.teardown_ucsmbinding() - self.teardown_network() - - def testd_update_ucsmbinding(self): - """update ucsm binding""" - net1 = self.quantum.create_network("t1", "netid1") - net2 = self.quantum.create_network("t1", "netid2") - binding1 = self.dbtest.create_ucsmbinding("1.2.3.4", net1["net-id"]) - binding1 = self.dbtest.update_ucsmbinding(binding1["ucsm-ip"], - net2["net-id"]) - bindings = self.dbtest.get_all_ucsmbindings() - count = 0 - for bind in bindings: - if net2["net-id"] == bind["network-id"]: - count += 1 - self.assertTrue(count == 1) - self.teardown_ucsmbinding() - self.teardown_network() - - def teste_create_dynamicvnic(self): - """create dynamic vnic""" - blade1 = self.dbtest.create_blade("1.2.3.4", "abcd", "chassis1", - "9.8.7.6", "UP", 2, "blade1") - vnic1 = self.dbtest.create_dynamicvnic("eth1", blade1["blade-id"], - "UP") - self.assertTrue(vnic1["device-name"] == "eth1") - self.teardown_dyanmicvnic() - - def testf_getall_dyanmicvnics(self): - """get all dynamic vnics""" - blade1 = self.dbtest.create_blade("1.2.3.4", "abcd", "chassis1", - "9.8.7.6", "UP", 2, "blade1") - vnic1 = self.dbtest.create_dynamicvnic("eth1", blade1["blade-id"], - "UP") - vnic2 = self.dbtest.create_dynamicvnic("eth2", blade1["blade-id"], - "UP") - vnics = self.dbtest.get_all_dynamicvnics() - count = 0 - for vnic in vnics: - if "eth" in vnic["device-name"]: - count += 1 - self.assertTrue(count == 2) - self.teardown_dyanmicvnic() - - def testg_delete_dyanmicvnic(self): - """delete dynamic vnic""" - blade1 = self.dbtest.create_blade("1.2.3.4", "abcd", "chassis1", - "9.8.7.6", "UP", 2, "blade1") - vnic1 = self.dbtest.create_dynamicvnic("eth1", blade1["blade-id"], - "UP") - self.dbtest.delete_dynamicvnic(vnic1["vnic-id"]) - vnics = self.dbtest.get_all_dynamicvnics() - count = 0 - for vnic in vnics: - if "eth " in vnic["device-name"]: - count += 1 - self.assertTrue(count == 0) - self.teardown_dyanmicvnic() - - def testh_updatedynamicvnic(self): - """update dynamic vnic""" - blade1 = self.dbtest.create_blade("1.2.3.4", "abcd", "chassis1", - "9.8.7.6", "UP", 2, "blade1") - vnic1 = self.dbtest.create_dynamicvnic("eth1", blade1["blade-id"], - "UP") - vnic1 = self.dbtest.update_dynamicvnic(vnic1["vnic-id"], "neweth1", - blade1["blade-id"], "DOWN") - vnics = self.dbtest.get_all_dynamicvnics() - count = 0 - for vnic in vnics: - if "new" in vnic["device-name"]: - count += 1 - self.assertTrue(count == 1) - self.teardown_dyanmicvnic() - - def testi_create_ucsblade(self): - """create ucs blade""" - blade1 = self.dbtest.create_blade("1.2.3.4", "abcd", "chassis1", - "9.8.7.6", "UP", 2, "blade1") - self.assertTrue(blade1["mgmt-ip"] == "1.2.3.4") - self.teardown_ucsblade() - - def testj_getall_ucsblade(self): - """get all ucs blades""" - blade1 = self.dbtest.create_blade("1.2.3.4", "abcd", "chassis1", - "9.8.7.6", "UP", 2, "blade1") - blade2 = self.dbtest.create_blade("2.3.4.5", "efgh", "chassis1", - "9.8.7.6", "UP", 3, "blade2") - blades = self.dbtest.get_all_blades() - count = 0 - for blade in blades: - if "chassis" in blade["chassis-id"]: - count += 1 - self.assertTrue(count == 2) - self.teardown_ucsblade() - - def testk_delete_ucsblade(self): - """delete ucs blades""" - blade1 = self.dbtest.create_blade("1.2.3.4", "abcd", "chassis1", - "9.8.7.6", "UP", 2, "blade1") - self.dbtest.delete_blade(blade1["blade-id"]) - blades = self.dbtest.get_all_blades() - count = 0 - for blade in blades: - if "chassis " in blade["chassis-id"]: - count += 1 - self.assertTrue(count == 0) - self.teardown_ucsblade() - - def testl_update_ucsblade(self): - """update ucs blade""" - blade1 = self.dbtest.create_blade("1.2.3.4", "abcd", "chassis1", - "9.8.7.6", "UP", 2, "blade1") - blade2 = self.dbtest.update_blade(blade1["blade-id"], "2.3.4.5", - "newabcd", "chassis1", "9.8.7.6", - "UP", 3, "blade1") - blades = self.dbtest.get_all_blades() - count = 0 - for blade in blades: - if "new" in blade["mac-addr"]: - count += 1 - self.assertTrue(count == 1) - self.teardown_ucsblade() - def testm_create_portbinding(self): """create port binding""" net1 = self.quantum.create_network("t1", "netid1") port1 = self.quantum.create_port(net1["net-id"]) - blade1 = self.dbtest.create_blade("1.2.3.4", "abcd", "chassis1", - "9.8.7.6", "UP", 2, "blade1") - vnic1 = self.dbtest.create_dynamicvnic("eth1", blade1["blade-id"], - "UP") port_bind1 = self.dbtest.create_port_binding(port1["port-id"], - vnic1["vnic-id"], "pp1", "vlan1", 10, "qos1") + "vnic1", "pp1", "vlan1", 10, "qos1") self.assertTrue(port_bind1["port-id"] == port1["port-id"]) self.teardown_portbinding() - self.teardown_dyanmicvnic() - self.teardown_ucsblade() self.teardown_network_port() def testn_getall_portbindings(self): @@ -1002,16 +610,10 @@ class UcsDBTest(unittest.TestCase): net1 = self.quantum.create_network("t1", "netid1") port1 = self.quantum.create_port(net1["net-id"]) port2 = self.quantum.create_port(net1["net-id"]) - blade1 = self.dbtest.create_blade("1.2.3.4", "abcd", "chassis1", - "9.8.7.6", "UP", 2, "blade1") - vnic1 = self.dbtest.create_dynamicvnic("eth1", blade1["blade-id"], - "UP") - vnic2 = self.dbtest.create_dynamicvnic("eth2", blade1["blade-id"], - "UP") port_bind1 = self.dbtest.create_port_binding(port1["port-id"], - vnic1["vnic-id"], "pp1", "vlan1", 10, "qos1") + "vnic1", "pp1", "vlan1", 10, "qos1") port_bind2 = self.dbtest.create_port_binding(port2["port-id"], - vnic2["vnic-id"], "pp2", "vlan2", 20, "qos2") + "vnic2", "pp2", "vlan2", 20, "qos2") port_bindings = self.dbtest.get_all_port_bindings() count = 0 for pbind in port_bindings: @@ -1019,20 +621,14 @@ class UcsDBTest(unittest.TestCase): count += 1 self.assertTrue(count == 2) self.teardown_portbinding() - self.teardown_dyanmicvnic() - self.teardown_ucsblade() self.teardown_network_port() def testo_delete_portbinding(self): """delete port binding""" net1 = self.quantum.create_network("t1", "netid1") port1 = self.quantum.create_port(net1["net-id"]) - blade1 = self.dbtest.create_blade("1.2.3.4", "abcd", "chassis1", - "9.8.7.6", "UP", 2, "blade1") - vnic1 = self.dbtest.create_dynamicvnic("eth1", blade1["blade-id"], - "UP") port_bind1 = self.dbtest.create_port_binding(port1["port-id"], - vnic1["vnic-id"], "pp1", "vlan1", 10, "qos1") + "vnic1", "pp1", "vlan1", 10, "qos1") self.dbtest.delete_port_binding(port1["port-id"]) port_bindings = self.dbtest.get_all_port_bindings() count = 0 @@ -1041,22 +637,16 @@ class UcsDBTest(unittest.TestCase): count += 1 self.assertTrue(count == 0) self.teardown_portbinding() - self.teardown_dyanmicvnic() - self.teardown_ucsblade() self.teardown_network_port() def testp_update_portbinding(self): """update port binding""" net1 = self.quantum.create_network("t1", "netid1") port1 = self.quantum.create_port(net1["net-id"]) - blade1 = self.dbtest.create_blade("1.2.3.4", "abcd", "chassis1", - "9.8.7.6", "UP", 2, "blade1") - vnic1 = self.dbtest.create_dynamicvnic("eth1", blade1["blade-id"], - "UP") port_bind1 = self.dbtest.create_port_binding(port1["port-id"], - vnic1["vnic-id"], "pp1", "vlan1", 10, "qos1") + "vnic1", "pp1", "vlan1", 10, "qos1") port_bind1 = self.dbtest.update_port_binding(port1["port-id"], - vnic1["vnic-id"], "newpp1", "newvlan1", 11, "newqos1") + "vnic1", "newpp1", "newvlan1", 11, "newqos1") port_bindings = self.dbtest.get_all_port_bindings() count = 0 for pbind in port_bindings: @@ -1064,35 +654,8 @@ class UcsDBTest(unittest.TestCase): count += 1 self.assertTrue(count == 1) self.teardown_portbinding() - self.teardown_dyanmicvnic() - self.teardown_ucsblade() self.teardown_network_port() - def teardown_ucsmbinding(self): - """tear down ucsm binding""" - LOG.debug("Tearing Down Ucsm Bindings") - binds = self.dbtest.get_all_ucsmbindings() - for bind in binds: - ucsmip = bind["ucsm-ip"] - self.dbtest.delete_ucsmbinding(ucsmip) - - def teardown_dyanmicvnic(self): - """tear down dynamic vnics""" - LOG.debug("Tearing Down Dynamic Vnics") - vnics = self.dbtest.get_all_dynamicvnics() - for vnic in vnics: - vnicid = vnic["vnic-id"] - self.dbtest.delete_dynamicvnic(vnicid) - self.teardown_ucsblade() - - def teardown_ucsblade(self): - """tear down ucs blades""" - LOG.debug("Tearing Down Blades") - blades = self.dbtest.get_all_blades() - for blade in blades: - bladeid = blade["blade-id"] - self.dbtest.delete_blade(bladeid) - def teardown_portbinding(self): """tear down port binding""" LOG.debug("Tearing Down Port Binding") @@ -1101,14 +664,6 @@ class UcsDBTest(unittest.TestCase): portid = port_binding["port-id"] self.dbtest.delete_port_binding(portid) - def teardown_network(self): - """tearDown Network table""" - LOG.debug("Tearing Down Network") - nets = self.quantum.get_all_networks("t1") - for net in nets: - netid = net["net-id"] - self.quantum.delete_network(netid) - def teardown_network_port(self): """tearDown for Network and Port table""" networks = self.quantum.get_all_networks("t1") @@ -1391,7 +946,7 @@ class L2networkDBTest(unittest.TestCase): self.assertTrue(used == True) used = l2network_db.release_vlanid(vlanid) self.assertTrue(used == False) - self.teardown_vlanid() + #counting on default teardown here to clear db def teardown_network(self): """tearDown Network table""" @@ -1437,14 +992,6 @@ class L2networkDBTest(unittest.TestCase): portid = pp_binding["port-id"] self.dbtest.delete_pp_binding("t1", portid, ppid) - def teardown_vlanid(self): - """tearDown VlanID table""" - LOG.debug("Tearing Down Vlan IDs") - vlanids = l2network_db.get_all_vlanids() - for vlanid in vlanids: - vlan_id = vlanid["vlan_id"] - l2network_db.delete_vlanid(vlan_id) - class QuantumDBTest(unittest.TestCase): """Class conisting of Quantum DB unit tests""" From 4a79f89f7bc3316fcb728c3d9421198ed5fc3bd2 Mon Sep 17 00:00:00 2001 From: Ying Liu Date: Thu, 25 Aug 2011 17:01:50 -0700 Subject: [PATCH 30/39] change get_host and get_instance_port function name --- extensions/novatenant.py | 18 +++++++-------- .../cisco/tests/unit/test_cisco_extension.py | 22 +++++++++---------- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/extensions/novatenant.py b/extensions/novatenant.py index 5cbfc4bd0a..4f21516bc5 100644 --- a/extensions/novatenant.py +++ b/extensions/novatenant.py @@ -65,8 +65,8 @@ class Novatenant(object): """ Returns Ext Resource Name """ parent_resource = dict(member_name="tenant", collection_name="extensions/csco/tenants") - member_actions = {'get_host': "PUT", - 'get_instance_port': "PUT"} + member_actions = {'schedule_host': "PUT", + 'associate_port': "PUT"} controller = NovatenantsController(QuantumManager.get_plugin()) return [extensions.ResourceExtension('novatenants', controller, parent=parent_resource, @@ -81,7 +81,7 @@ class NovatenantsController(common.QuantumController): 'param-name': 'novatenant_name', 'required': True}] - _get_host_ops_param_list = [{ + _schedule_host_ops_param_list = [{ 'param-name': 'instance_id', 'required': True}, { 'param-name': 'instance_desc', @@ -126,21 +126,21 @@ class NovatenantsController(common.QuantumController): return "novatenant is a dummy resource" #added for cisco's extension - def get_host(self, request, tenant_id, id): + def schedule_host(self, request, tenant_id, id): content_type = request.best_match_content_type() print "Content type:%s" % content_type try: req_params = \ self._parse_request_params(request, - self._get_host_ops_param_list) + 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: - host = self._plugin.get_host(tenant_id, instance_id, instance_desc) + host = self._plugin.schedule_host(tenant_id, instance_id, instance_desc) builder = novatenant_view.get_view_builder(request) result = builder.build_host(host) return result @@ -148,14 +148,14 @@ class NovatenantsController(common.QuantumController): except qexception.PortNotFound as exp: return faults.Fault(faults.PortNotFound(exp)) - def get_instance_port(self, request, tenant_id, id): + def associate_port(self, request, tenant_id, id): content_type = request.best_match_content_type() print "Content type:%s" % content_type try: req_params = \ self._parse_request_params(request, - self._get_host_ops_param_list) + self._schedule_host_ops_param_list) except exc.HTTPError as exp: return faults.Fault(exp) instance_id = req_params['instance_id'] @@ -163,7 +163,7 @@ class NovatenantsController(common.QuantumController): instance_desc = req_params['instance_desc'] try: vif = self._plugin. \ - get_instance_port(tenant_id, instance_id, instance_desc) + associate_port(tenant_id, instance_id, instance_desc) builder = novatenant_view.get_view_builder(request) result = builder.build_vif(vif) return result diff --git a/quantum/plugins/cisco/tests/unit/test_cisco_extension.py b/quantum/plugins/cisco/tests/unit/test_cisco_extension.py index f69ac3df0c..172a2e7122 100644 --- a/quantum/plugins/cisco/tests/unit/test_cisco_extension.py +++ b/quantum/plugins/cisco/tests/unit/test_cisco_extension.py @@ -405,8 +405,8 @@ class NovatenantExtensionTest(unittest.TestCase): def setUp(self): parent_resource = dict(member_name="tenant", collection_name="extensions/csco/tenants") - member_actions = {'get_host': "PUT", - 'get_instance_port': "PUT"} + member_actions = {'schedule_host': "PUT", + 'associate_port': "PUT"} controller = novatenant.NovatenantsController( QuantumManager.get_plugin()) res_ext = extensions.ResourceExtension('novatenants', controller, @@ -420,29 +420,29 @@ class NovatenantExtensionTest(unittest.TestCase): 'instance_desc': {'key1': '1', 'key2': '2'}}} - def test_get_host(self): - LOG.debug("test_get_host - START") + def test_schedule_host(self): + LOG.debug("test_schedule_host - START") req_body = json.dumps(self.test_instance_data) - host_path = self.novatenants_path + "001/get_host" + host_path = self.novatenants_path + "001/schedule_host" host_response = self.test_app.put( host_path, req_body, content_type=self.contenttype) self.assertEqual(200, host_response.status_int) - LOG.debug("test_get_host - END") + LOG.debug("test_schedule_host - END") - def test_get_hostBADRequest(self): - LOG.debug("test_get_hostBADRequest - START") - host_path = self.novatenants_path + "001/get_host" + def test_schedule_hostBADRequest(self): + LOG.debug("test_schedule_hostBADRequest - START") + host_path = self.novatenants_path + "001/schedule_host" host_response = self.test_app.put( host_path, 'BAD_REQUEST', content_type=self.contenttype, status='*') self.assertEqual(400, host_response.status_int) - LOG.debug("test_get_hostBADRequest - END") + LOG.debug("test_schedule_hostBADRequest - END") def test_instance_port(self): LOG.debug("test_instance_port - START") req_body = json.dumps(self.test_instance_data) - instance_port_path = self.novatenants_path + "001/get_instance_port" + instance_port_path = self.novatenants_path + "001/associate_port" instance_port_response = self.test_app.put( instance_port_path, req_body, content_type=self.contenttype) From bfc07107e3f80a16dfe0b86f4f07e9b5a31f9109 Mon Sep 17 00:00:00 2001 From: Sumit Naiksatam Date: Thu, 25 Aug 2011 17:42:16 -0700 Subject: [PATCH 31/39] Changes qos description to string; changes extension API names for get_host and get_instance_port --- quantum/plugins/cisco/l2network_plugin.py | 10 +++++----- quantum/plugins/cisco/models/l2network_multi_blade.py | 8 ++++---- quantum/plugins/cisco/models/l2network_single_blade.py | 8 ++++---- quantum/plugins/cisco/ucs/cisco_ucs_inventory.py | 8 ++++---- 4 files changed, 17 insertions(+), 17 deletions(-) diff --git a/quantum/plugins/cisco/l2network_plugin.py b/quantum/plugins/cisco/l2network_plugin.py index 2a5ada6ff3..84f5602b90 100644 --- a/quantum/plugins/cisco/l2network_plugin.py +++ b/quantum/plugins/cisco/l2network_plugin.py @@ -381,7 +381,7 @@ class L2Network(QuantumPluginBase): def create_qos(self, tenant_id, qos_name, qos_desc): """Create a QoS level""" LOG.debug("create_qos() called\n") - qos = cdb.add_qos(tenant_id, qos_name, qos_desc) + qos = cdb.add_qos(tenant_id, qos_name, str(qos_desc)) return qos def delete_qos(self, tenant_id, qos_id): @@ -451,19 +451,19 @@ class L2Network(QuantumPluginBase): credential = cdb.update_credential(tenant_id, credential_id, new_name) return credential - def get_host(self, tenant_id, instance_id, instance_desc): + def schedule_host(self, tenant_id, instance_id, instance_desc): """Provides the hostname on which a dynamic vnic is reserved""" - LOG.debug("get_host() called\n") + LOG.debug("schedule_host() called\n") host_list = self._invoke_device_plugins(self._func_name(), [tenant_id, instance_id, instance_desc]) return host_list - def get_instance_port(self, tenant_id, instance_id, instance_desc): + def associate_port(self, tenant_id, instance_id, instance_desc): """ Get the portprofile name and the device namei for the dynamic vnic """ - LOG.debug("get_instance_port() called\n") + LOG.debug("associate_port() called\n") return self._invoke_device_plugins(self._func_name(), [tenant_id, instance_id, instance_desc]) diff --git a/quantum/plugins/cisco/models/l2network_multi_blade.py b/quantum/plugins/cisco/models/l2network_multi_blade.py index 9f8958b2bf..acd24d5ee6 100644 --- a/quantum/plugins/cisco/models/l2network_multi_blade.py +++ b/quantum/plugins/cisco/models/l2network_multi_blade.py @@ -158,16 +158,16 @@ class L2NetworkMultiBlade(L2NetworkModelBase): self._invoke_plugin_per_device(const.UCS_PLUGIN, self._func_name(), args) - def get_host(self, args): + def schedule_host(self, args): """Provides the hostname on which a dynamic vnic is reserved""" - LOG.debug("get_host() called\n") + LOG.debug("schedule_host() called\n") return self._invoke_inventory(const.UCS_PLUGIN, self._func_name(), args) - def get_instance_port(self, args): + def associate_port(self, args): """ Get the portprofile name and the device namei for the dynamic vnic """ - LOG.debug("get_instance_port() called\n") + LOG.debug("associate_port() called\n") return self._invoke_inventory(const.UCS_PLUGIN, self._func_name(), args) diff --git a/quantum/plugins/cisco/models/l2network_single_blade.py b/quantum/plugins/cisco/models/l2network_single_blade.py index 9cb0a89e03..617d1a55d6 100644 --- a/quantum/plugins/cisco/models/l2network_single_blade.py +++ b/quantum/plugins/cisco/models/l2network_single_blade.py @@ -149,16 +149,16 @@ class L2NetworkSingleBlade(L2NetworkModelBase): self._invoke_plugin_per_device(const.UCS_PLUGIN, self._func_name(), args) - def get_host(self, args): + def schedule_host(self, args): """Provides the hostname on which a dynamic vnic is reserved""" - LOG.debug("get_host() called\n") + LOG.debug("schedule_host() called\n") return self._invoke_inventory(const.UCS_PLUGIN, self._func_name(), args) - def get_instance_port(self, args): + def associate_port(self, args): """ Get the portprofile name and the device namei for the dynamic vnic """ - LOG.debug("get_instance_port() called\n") + LOG.debug("associate_port() called\n") return self._invoke_inventory(const.UCS_PLUGIN, self._func_name(), args) diff --git a/quantum/plugins/cisco/ucs/cisco_ucs_inventory.py b/quantum/plugins/cisco/ucs/cisco_ucs_inventory.py index 7b13982d66..2a90824bb8 100644 --- a/quantum/plugins/cisco/ucs/cisco_ucs_inventory.py +++ b/quantum/plugins/cisco/ucs/cisco_ucs_inventory.py @@ -597,9 +597,9 @@ class UCSInventory(L2NetworkDeviceInventoryBase): LOG.debug("unplug_interface() called\n") return self._get_blade_for_port(args) - def get_host(self, args): + def schedule_host(self, args): """Provides the hostname on which a dynamic vnic is reserved""" - LOG.debug("get_host() called\n") + LOG.debug("schedule_host() called\n") instance_id = args[1] tenant_id = args[2][const.PROJECT_ID] host_name = self._get_host_name_for_rsvd_intf(tenant_id, instance_id) @@ -607,11 +607,11 @@ class UCSInventory(L2NetworkDeviceInventoryBase): LOG.debug("host_list is: %s" % host_list) return host_list - def get_instance_port(self, args): + def associate_port(self, args): """ Get the portprofile name and the device name for the dynamic vnic """ - LOG.debug("get_instance_port() called\n") + LOG.debug("associate_port() called\n") instance_id = args[1] tenant_id = args[2][const.PROJECT_ID] vif_id = args[2][const.VIF_ID] From 0cc6ccc1c8b0b43ecdc62e58e60d047ab5382759 Mon Sep 17 00:00:00 2001 From: Shweta P Date: Thu, 25 Aug 2011 23:36:20 -0700 Subject: [PATCH 32/39] Added Extension & ucs driver test changes and fixes --- quantum/plugins/cisco/README | 4 + .../cisco/tests/unit/test_cisco_extension.py | 104 ++++++++++++++++-- .../cisco/tests/unit/test_ucs_driver.py | 10 -- 3 files changed, 97 insertions(+), 21 deletions(-) diff --git a/quantum/plugins/cisco/README b/quantum/plugins/cisco/README index 503894a662..ef8a49afb3 100755 --- a/quantum/plugins/cisco/README +++ b/quantum/plugins/cisco/README @@ -285,6 +285,10 @@ result the quantum/plugins/cisco/run_tests.py script. python run_tests.py quantum.plugins.cisco.tests.unit.test_cisco_extension + To run specific tests + python run_tests.py + quantum.plugins.cisco.tests.unit.test_cisco_extension:. + Bingo bango bongo! That's it! Thanks for taking the leap into Quantum. ...Oh, boy! diff --git a/quantum/plugins/cisco/tests/unit/test_cisco_extension.py b/quantum/plugins/cisco/tests/unit/test_cisco_extension.py index 0408ef3f6f..f4d958ee02 100644 --- a/quantum/plugins/cisco/tests/unit/test_cisco_extension.py +++ b/quantum/plugins/cisco/tests/unit/test_cisco_extension.py @@ -80,8 +80,8 @@ class PortprofileExtensionTest(unittest.TestCase): self.profile_path = '/extensions/csco/tenants/tt/portprofiles' self.portprofile_path = '/extensions/csco/tenants/tt/portprofiles/' self.test_port_profile = {'portprofile': - {'portprofile_name': 'cisco_test_portprofile', - 'qos_name': 'test-qos1'}} + {'portprofile_name': 'cisco_test_portprofile', + 'qos_name': 'test-qos1'}} self.tenant_id = "test_tenant" self.network_name = "test_network" options = {} @@ -107,9 +107,10 @@ class PortprofileExtensionTest(unittest.TestCase): content_type=self.contenttype) index_response = self.test_app.get(self.profile_path) + index_resp_body = wsgi.Serializer().deserialize(index_response.body, + self.contenttype) self.assertEqual(200, index_response.status_int) - # Clean Up - Delete the Port Profiles resp_body1 = wsgi.Serializer().deserialize(create_response1.body, self.contenttype) portprofile_path1_temp = self.portprofile_path +\ @@ -117,9 +118,17 @@ class PortprofileExtensionTest(unittest.TestCase): portprofile_path1 = str(portprofile_path1_temp) resp_body2 = wsgi.Serializer().deserialize(create_response2.body, self.contenttype) + list_all_portprofiles = [resp_body1['portprofiles']['portprofile'], + resp_body2['portprofiles']['portprofile']] + self.assertTrue(index_resp_body['portprofiles'][0] in + list_all_portprofiles) + self.assertTrue(index_resp_body['portprofiles'][1] in + list_all_portprofiles) portprofile_path2_temp = self.portprofile_path +\ resp_body2['portprofiles']['portprofile']['id'] portprofile_path2 = str(portprofile_path2_temp) + + # Clean Up - Delete the Port Profiles self.tear_down_profile(portprofile_path1) self.tear_down_profile(portprofile_path2) LOG.debug("test_list_portprofile - END") @@ -168,6 +177,14 @@ class PortprofileExtensionTest(unittest.TestCase): resp_body['portprofiles']['portprofile']['id'] show_port_path = str(show_path_temp) show_response = self.test_app.get(show_port_path) + show_resp_dict = wsgi.Serializer().deserialize(show_response.body, + self.contenttype) + self.assertEqual( + show_resp_dict['portprofiles']['portprofile']['qos_name'], + self.test_port_profile['portprofile']['qos_name']) + self.assertEqual( + show_resp_dict['portprofiles']['portprofile']['name'], + self.test_port_profile['portprofile']['portprofile_name']) self.assertEqual(200, show_response.status_int) # Clean Up - Delete the Port Profile @@ -204,6 +221,14 @@ class PortprofileExtensionTest(unittest.TestCase): resp_body['portprofiles']['portprofile']['id'] rename_path = str(rename_path_temp) rename_response = self.test_app.put(rename_path, rename_req_body) + rename_resp_dict = wsgi.Serializer().deserialize(rename_response.body, + self.contenttype) + self.assertEqual( + rename_resp_dict['portprofiles']['portprofile']['qos_name'], + self.test_port_profile['portprofile']['qos_name']) + self.assertEqual( + rename_resp_dict['portprofiles']['portprofile']['name'], + rename_port_profile['portprofile']['portprofile_name']) self.assertEqual(200, rename_response.status_int) # Clean Up - Delete the Port Profile @@ -288,8 +313,8 @@ class PortprofileExtensionTest(unittest.TestCase): req.headers = {} req.headers['Accept'] = content_type req.body = body - return req LOG.debug("test_create_request - END") + return req def _create_network(self, name=None): @@ -308,8 +333,8 @@ class PortprofileExtensionTest(unittest.TestCase): network_res = network_req.get_response(self.api) network_data = wsgi.Serializer().deserialize(network_res.body, self.contenttype) - return network_data['networks']['network']['id'] LOG.debug("Creating network - END") + return network_data['networks']['network']['id'] def _create_port(self, network_id, port_state): @@ -325,8 +350,8 @@ class PortprofileExtensionTest(unittest.TestCase): port_res = port_req.get_response(self.api) port_data = wsgi.Serializer().deserialize(port_res.body, self.contenttype) - return port_data['ports']['port']['id'] LOG.debug("Creating port for network - END") + return port_data['ports']['port']['id'] def test_associate_portprofile(self): @@ -463,9 +488,13 @@ class NovatenantExtensionTest(unittest.TestCase): SimpleExtensionManager(res_ext)) self.contenttype = 'application/json' self.novatenants_path = '/extensions/csco/tenants/tt/novatenants/' + self.test_associate_port_data = {'novatenant': {'instance_id': 1, + 'instance_desc': {'project_id': 'demo', + 'user_id': 'root', 'vif_id': '23432423'}}} self.test_associate_data = {'novatenant': {'instance_id': 1, - 'instance_desc': {'key1': '1', - 'key2': '2'}}} + 'instance_desc': {'project_id': 'demo', + 'user_id': 'root'}}} + self._l2network_plugin = l2network_plugin.L2Network() def test_schedule_host(self): """ Test get host""" @@ -473,8 +502,8 @@ class NovatenantExtensionTest(unittest.TestCase): req_body = json.dumps(self.test_associate_data) host_path = self.novatenants_path + "001/schedule_host" host_response = self.test_app.put( - host_path, req_body, - content_type=self.contenttype) + host_path, req_body, + content_type=self.contenttype) self.assertEqual(200, host_response.status_int) LOG.debug("test_schedule_host - END") @@ -491,7 +520,7 @@ class NovatenantExtensionTest(unittest.TestCase): def test_associate_port(self): """ Test get associate port """ LOG.debug("test_associate_port - START") - req_body = json.dumps(self.test_associate_data) + req_body = json.dumps(self.test_associate_port_data) associate_port_path = self.novatenants_path + "001/associate_port" associate_port_response = self.test_app.put( associate_port_path, req_body, @@ -499,6 +528,11 @@ class NovatenantExtensionTest(unittest.TestCase): self.assertEqual(200, associate_port_response.status_int) LOG.debug("test_associate_port - END") + def tearDown(self): + + """ Tear down """ + db.clear_db() + class QosExtensionTest(unittest.TestCase): @@ -519,6 +553,7 @@ class QosExtensionTest(unittest.TestCase): self.qos_second_path = '/extensions/csco/tenants/tt/qos/' self.test_qos_data = {'qos': {'qos_name': 'cisco_test_qos', 'qos_desc': {'PPS': 50, 'TTL': 5}}} + self._l2network_plugin = l2network_plugin.L2Network() def test_create_qos(self): @@ -565,6 +600,8 @@ class QosExtensionTest(unittest.TestCase): create_resp2 = self.test_app.post(self.qos_path, req_body2, content_type=self.contenttype) index_response = self.test_app.get(self.qos_path) + index_resp_body = wsgi.Serializer().deserialize(index_response.body, + self.contenttype) self.assertEqual(200, index_response.status_int) # Clean Up - Delete the qos's @@ -575,6 +612,9 @@ class QosExtensionTest(unittest.TestCase): qos_path1 = str(qos_path1_temp) resp_body2 = wsgi.Serializer().deserialize(create_resp2.body, self.contenttype) + list_all_qos = [resp_body1['qoss']['qos'], resp_body2['qoss']['qos']] + self.assertTrue(index_resp_body['qoss'][0] in list_all_qos) + self.assertTrue(index_resp_body['qoss'][1] in list_all_qos) qos_path2_temp = self.qos_second_path +\ resp_body2['qoss']['qos']['id'] qos_path2 = str(qos_path2_temp) @@ -596,6 +636,12 @@ class QosExtensionTest(unittest.TestCase): resp_body['qoss']['qos']['id'] show_qos_path = str(show_path_temp) show_response = self.test_app.get(show_qos_path) + show_resp_dict = wsgi.Serializer().deserialize(show_response.body, + self.contenttype) + self.assertEqual( + show_resp_dict['qoss']['qos']['name'], + self.test_qos_data['qos']['qos_name']) + self.assertEqual(200, show_response.status_int) # Clean Up - Delete the qos @@ -630,6 +676,11 @@ class QosExtensionTest(unittest.TestCase): rename_path = str(rename_path_temp) rename_response = self.test_app.put(rename_path, rename_req_body) self.assertEqual(200, rename_response.status_int) + rename_resp_dict = wsgi.Serializer().deserialize(rename_response.body, + self.contenttype) + self.assertEqual( + rename_resp_dict['qoss']['qos']['name'], + 'cisco_rename_qos') self.tearDownQos(rename_path) LOG.debug("test_update_qos - END") @@ -703,6 +754,9 @@ class QosExtensionTest(unittest.TestCase): self.test_app.delete(delete_profile_path) + def tearDown(self): + db.clear_db() + class CredentialExtensionTest(unittest.TestCase): @@ -725,6 +779,7 @@ class CredentialExtensionTest(unittest.TestCase): {'credential_name': 'cred8', 'user_name': 'newUser2', 'password': 'newPasswd1'}} + self._l2network_plugin = l2network_plugin.L2Network() def test_list_credentials(self): @@ -745,6 +800,8 @@ class CredentialExtensionTest(unittest.TestCase): content_type=self.contenttype) index_response = self.test_app.get( self.credential_path) + index_resp_body = wsgi.Serializer().deserialize(index_response.body, + self.contenttype) self.assertEqual(200, index_response.status_int) #CLean Up - Deletion of the Credentials resp_body1 = wsgi.Serializer().deserialize( @@ -754,6 +811,12 @@ class CredentialExtensionTest(unittest.TestCase): delete_path1 = str(delete_path1_temp) resp_body2 = wsgi.Serializer().deserialize( create_response2.body, self.contenttype) + list_all_credential = [resp_body1['credentials']['credential'], + resp_body2['credentials']['credential']] + self.assertTrue(index_resp_body['credentials'][0] in + list_all_credential) + self.assertTrue(index_resp_body['credentials'][1] in + list_all_credential) delete_path2_temp = self.cred_second_path +\ resp_body2['credentials']['credential']['id'] delete_path2 = str(delete_path2_temp) @@ -806,6 +869,14 @@ class CredentialExtensionTest(unittest.TestCase): resp_body['credentials']['credential']['id'] show_cred_path = str(show_path_temp) show_response = self.test_app.get(show_cred_path) + show_resp_dict = wsgi.Serializer().deserialize(show_response.body, + self.contenttype) + self.assertEqual( + show_resp_dict['credentials']['credential']['name'], + self.test_credential_data['credential']['user_name']) + self.assertEqual( + show_resp_dict['credentials']['credential']['password'], + self.test_credential_data['credential']['password']) self.assertEqual(200, show_response.status_int) LOG.debug("test_show_credential - END") @@ -840,6 +911,14 @@ class CredentialExtensionTest(unittest.TestCase): resp_body['credentials']['credential']['id'] rename_path = str(rename_path_temp) rename_response = self.test_app.put(rename_path, rename_req_body) + rename_resp_dict = wsgi.Serializer().deserialize(rename_response.body, + self.contenttype) + self.assertEqual( + rename_resp_dict['credentials']['credential']['name'], + 'cred3') + self.assertEqual( + rename_resp_dict['credentials']['credential']['password'], + self.test_credential_data['credential']['password']) self.assertEqual(200, rename_response.status_int) # Clean Up - Delete the Credentials self.tearDownCredential(rename_path) @@ -912,6 +991,9 @@ class CredentialExtensionTest(unittest.TestCase): def tearDownCredential(self, delete_path): self.test_app.delete(delete_path) + def tearDown(self): + db.clear_db() + def app_factory(global_conf, **local_conf): conf = global_conf.copy() diff --git a/quantum/plugins/cisco/tests/unit/test_ucs_driver.py b/quantum/plugins/cisco/tests/unit/test_ucs_driver.py index 9da92e5b06..c7adcc57d9 100644 --- a/quantum/plugins/cisco/tests/unit/test_ucs_driver.py +++ b/quantum/plugins/cisco/tests/unit/test_ucs_driver.py @@ -155,13 +155,3 @@ class TestUCSDriver(unittest.TestCase): self.profile_name, self.profile_client_name) self.assertEqual(profile_details, expected_output) LOG.debug("test_create_profile_post - END") - - def test_get_next_dynamic_nic(self): - """ - Tests get next dynamic nic - """ - - LOG.debug("test_get_next_dynamic_nic - START") - dynamic_nic_id = self.ucsm_driver._get_next_dynamic_nic() - self.assertTrue(len(dynamic_nic_id) > 0) - LOG.debug("test_get_next_dynamic_nic - END") From 91b4918241616aaa14882f6ae345f2843904cc7a Mon Sep 17 00:00:00 2001 From: Ying Liu Date: Fri, 26 Aug 2011 12:24:29 -0700 Subject: [PATCH 33/39] fix pep8 issues --- extensions/_credential_view.py | 8 +++---- extensions/_novatenant_view.py | 8 +++---- extensions/_pprofiles.py | 7 +++--- extensions/_qos_view.py | 6 ++--- extensions/credential.py | 4 ++-- extensions/novatenant.py | 33 +++++++++++++-------------- extensions/portprofile.py | 41 +++++++++++++++++----------------- extensions/qos.py | 14 ++++++------ 8 files changed, 57 insertions(+), 64 deletions(-) diff --git a/extensions/_credential_view.py b/extensions/_credential_view.py index 3c8ce49a49..0175ecd84f 100644 --- a/extensions/_credential_view.py +++ b/extensions/_credential_view.py @@ -28,7 +28,7 @@ def get_view_builder(req): class ViewBuilder(object): """ - ViewBuilder for Credential, + ViewBuilder for Credential, derived from quantum.views.networks """ def __init__(self, base_url): @@ -39,20 +39,18 @@ class ViewBuilder(object): def build(self, credential_data, is_detail=False): """Generic method used to generate a credential entity.""" - if is_detail: credential = self._build_detail(credential_data) else: credential = self._build_simple(credential_data) return credential - + def _build_simple(self, credential_data): """Return a simple description of credential.""" return dict(credential=dict(id=credential_data['credential_id'])) - + def _build_detail(self, credential_data): """Return a detailed description of credential.""" - return dict(credential=dict(id=credential_data['credential_id'], name=credential_data['user_name'], password=credential_data['password'])) diff --git a/extensions/_novatenant_view.py b/extensions/_novatenant_view.py index a25654916e..b32ff8b644 100644 --- a/extensions/_novatenant_view.py +++ b/extensions/_novatenant_view.py @@ -29,7 +29,7 @@ def get_view_builder(req): class ViewBuilder(object): """ - ViewBuilder for novatenant, + ViewBuilder for novatenant, derived from quantum.views.networks """ def __init__(self, base_url): @@ -37,11 +37,11 @@ class ViewBuilder(object): :param base_url: url of the root wsgi application """ self.base_url = base_url - + def build_host(self, host_data): """Return host description.""" return dict(host_list=host_data[const.HOST_LIST]) - + def build_vif(self, vif_data): """Return VIF description.""" - return dict(vif_desc=vif_data[const.VIF_DESC]) + return dict(vif_desc=vif_data[const.VIF_DESC]) diff --git a/extensions/_pprofiles.py b/extensions/_pprofiles.py index cf851bae08..285cef0b6e 100644 --- a/extensions/_pprofiles.py +++ b/extensions/_pprofiles.py @@ -28,7 +28,7 @@ def get_view_builder(req): class ViewBuilder(object): """ - ViewBuilder for Portprofile, + ViewBuilder for Portprofile, derived from quantum.views.networks """ def __init__(self, base_url): @@ -39,17 +39,16 @@ class ViewBuilder(object): def build(self, portprofile_data, is_detail=False): """Generic method used to generate a portprofile entity.""" - if is_detail: portprofile = self._build_detail(portprofile_data) else: portprofile = self._build_simple(portprofile_data) return portprofile - + def _build_simple(self, portprofile_data): """Return a simple description of a portprofile""" return dict(portprofile=dict(id=portprofile_data['profile_id'])) - + def _build_detail(self, portprofile_data): """Return a detailed info of a portprofile.""" if (portprofile_data['assignment'] == None): diff --git a/extensions/_qos_view.py b/extensions/_qos_view.py index 3ad0d30c3c..24469e4bc8 100644 --- a/extensions/_qos_view.py +++ b/extensions/_qos_view.py @@ -28,7 +28,7 @@ def get_view_builder(req): class ViewBuilder(object): """ - ViewBuilder for QoS, + ViewBuilder for QoS, derived from quantum.views.networks """ def __init__(self, base_url): @@ -44,11 +44,11 @@ class ViewBuilder(object): else: qos = self._build_simple(qos_data) return qos - + def _build_simple(self, qos_data): """Return a simple description of qos.""" return dict(qos=dict(id=qos_data['qos_id'])) - + def _build_detail(self, qos_data): """Return a detailed description of qos.""" return dict(qos=dict(id=qos_data['qos_id'], diff --git a/extensions/credential.py b/extensions/credential.py index 31c49bdd09..287cb4263b 100644 --- a/extensions/credential.py +++ b/extensions/credential.py @@ -125,7 +125,7 @@ class CredentialController(common.QuantumController): """ Creates a new credential for a given tenant """ try: req_params = \ - self._parse_request_params(request, + self._parse_request_params(request, self._credential_ops_param_list) except exc.HTTPError as exp: return faults.Fault(exp) @@ -142,7 +142,7 @@ class CredentialController(common.QuantumController): """ Updates the name for the credential with the given id """ try: req_params = \ - self._parse_request_params(request, + self._parse_request_params(request, self._credential_ops_param_list) except exc.HTTPError as exp: return faults.Fault(exp) diff --git a/extensions/novatenant.py b/extensions/novatenant.py index 828efec36a..9d45f60cd0 100644 --- a/extensions/novatenant.py +++ b/extensions/novatenant.py @@ -35,33 +35,33 @@ class Novatenant(object): @classmethod def get_name(cls): - """ Returns Ext Resource Name """ + """ Returns Ext Resource Name """ return "Cisco Nova Tenant" - + @classmethod def get_alias(cls): """ Returns Ext Resource alias""" return "Cisco Nova Tenant" - + @classmethod def get_description(cls): """ Returns Ext Resource Description """ return "novatenant resource is used by nova side to invoke quantum api" - + @classmethod def get_namespace(cls): """ Returns Ext Resource Namespace """ return "http://docs.ciscocloud.com/api/ext/novatenant/v1.0" - + @classmethod def get_updated(cls): """ Returns Ext Resource Updated Time """ return "2011-08-09T13:25:27-06:00" - + @classmethod def get_resources(cls): """ Returns Ext Resource """ - parent_resource = dict(member_name="tenant", + parent_resource = dict(member_name="tenant", collection_name="extensions/csco/tenants") member_actions = {'schedule_host': "PUT", 'associate_port': "PUT"} @@ -78,13 +78,13 @@ class NovatenantsController(common.QuantumController): _Novatenant_ops_param_list = [{ 'param-name': 'novatenant_name', 'required': True}] - + _schedule_host_ops_param_list = [{ 'param-name': 'instance_id', 'required': True}, { 'param-name': 'instance_desc', 'required': True}] - + _serialization_metadata = { "application/xml": { "attributes": { @@ -96,7 +96,7 @@ class NovatenantsController(common.QuantumController): def __init__(self, plugin): self._resource_name = 'novatenant' self._plugin = plugin - + #added for cisco's extension # pylint: disable-msg=E1101,W0613 def show(self, request, tenant_id, id): @@ -114,12 +114,11 @@ class NovatenantsController(common.QuantumController): def delete(self, request, tenant_id, id): """ Destroys the Novatenant with the given id """ return "novatenant is a dummy resource" - + #added for cisco's extension def schedule_host(self, request, tenant_id, id): content_type = request.best_match_content_type() print "Content type:%s" % content_type - try: req_params = \ self._parse_request_params(request, @@ -127,20 +126,19 @@ class NovatenantsController(common.QuantumController): except exc.HTTPError as exp: return faults.Fault(exp) instance_id = req_params['instance_id'] - instance_desc = req_params['instance_desc'] try: - host = self._plugin.schedule_host(tenant_id, instance_id, instance_desc) + host = self._plugin.\ + schedule_host(tenant_id, instance_id, instance_desc) builder = novatenant_view.get_view_builder(request) result = builder.build_host(host) return result except qexception.PortNotFound as exp: return faults.Fault(faults.PortNotFound(exp)) - + def associate_port(self, request, tenant_id, id): content_type = request.best_match_content_type() print "Content type:%s" % content_type - try: req_params = \ self._parse_request_params(request, @@ -148,7 +146,6 @@ class NovatenantsController(common.QuantumController): 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. \ @@ -156,6 +153,6 @@ class NovatenantsController(common.QuantumController): builder = novatenant_view.get_view_builder(request) result = builder.build_vif(vif) return result - + except qexception.PortNotFound as exp: return faults.Fault(faults.PortNotFound(exp)) diff --git a/extensions/portprofile.py b/extensions/portprofile.py index 4dd9c7b41c..8ecf65061a 100644 --- a/extensions/portprofile.py +++ b/extensions/portprofile.py @@ -34,36 +34,36 @@ class Portprofile(object): """extension class Portprofile""" def __init__(self): pass - + @classmethod def get_name(cls): """ Returns Ext Resource Name """ return "Cisco Port Profile" - + @classmethod def get_alias(cls): """ Returns Ext Resource alias """ return "Cisco Port Profile" - + @classmethod def get_description(cls): """ Returns Ext Resource Description """ return "Portprofile include QoS information" - + @classmethod def get_namespace(cls): """ Returns Ext Resource Namespace """ return "http://docs.ciscocloud.com/api/ext/portprofile/v1.0" - + @classmethod def get_updated(cls): """ Returns Ext Resource Updated time """ return "2011-07-23T13:25:27-06:00" - + @classmethod def get_resources(cls): """ Returns all defined resources """ - parent_resource = dict(member_name="tenant", + parent_resource = dict(member_name="tenant", collection_name="extensions/csco/tenants") member_actions = {'associate_portprofile': "PUT", 'disassociate_portprofile': "PUT"} @@ -71,16 +71,16 @@ class Portprofile(object): return [extensions.ResourceExtension('portprofiles', controller, parent=parent_resource, member_actions=member_actions)] - - + + class PortprofilesController(common.QuantumController): """ portprofile API controller based on QuantumController """ - + def __init__(self, plugin): self._resource_name = 'portprofile' self._plugin = plugin - + self._portprofile_ops_param_list = [{ 'param-name': 'portprofile_name', 'required': True}, { @@ -88,13 +88,13 @@ class PortprofilesController(common.QuantumController): 'required': True}, { 'param-name': 'assignment', 'required': False}] - + self._assignprofile_ops_param_list = [{ 'param-name': 'network-id', 'required': True}, { 'param-name': 'port-id', 'required': True}] - + self._serialization_metadata = { "application/xml": { "attributes": { @@ -102,7 +102,7 @@ class PortprofilesController(common.QuantumController): }, }, } - + def index(self, request, tenant_id): """ Returns a list of portprofile ids """ return self._items(request, tenant_id, is_detail=False) @@ -114,7 +114,7 @@ class PortprofilesController(common.QuantumController): result = [builder.build(portprofile, is_detail)['portprofile'] for portprofile in portprofiles] return dict(portprofiles=result) - + # pylint: disable-msg=E1101 def show(self, request, tenant_id, id): """ Returns portprofile details for the given portprofile id """ @@ -133,7 +133,7 @@ class PortprofilesController(common.QuantumController): #look for portprofile name in request try: req_params = \ - self._parse_request_params(request, + self._parse_request_params(request, self._portprofile_ops_param_list) except exc.HTTPError as exp: return faults.Fault(exp) @@ -149,7 +149,7 @@ class PortprofilesController(common.QuantumController): """ Updates the name for the portprofile with the given id """ try: req_params = \ - self._parse_request_params(request, + self._parse_request_params(request, self._portprofile_ops_param_list) except exc.HTTPError as exp: return faults.Fault(exp) @@ -171,12 +171,12 @@ class PortprofilesController(common.QuantumController): return exc.HTTPAccepted() except exception.PortProfileNotFound as exp: return faults.Fault(faults.PortprofileNotFound(exp)) - + def associate_portprofile(self, request, tenant_id, id): """ associate a portprofile to the port """ content_type = request.best_match_content_type() print "Content type:%s" % content_type - + try: req_params = \ self._parse_request_params(request, @@ -194,12 +194,11 @@ class PortprofilesController(common.QuantumController): return faults.Fault(faults.PortprofileNotFound(exp)) except qexception.PortNotFound as exp: return faults.Fault(faults.PortNotFound(exp)) - + def disassociate_portprofile(self, request, tenant_id, id): """ Disassociate a portprofile from a port """ content_type = request.best_match_content_type() print "Content type:%s" % content_type - try: req_params = \ self._parse_request_params(request, diff --git a/extensions/qos.py b/extensions/qos.py index 6e8cb72334..db624fe75e 100644 --- a/extensions/qos.py +++ b/extensions/qos.py @@ -36,7 +36,7 @@ class Qos(object): """Qos extension file""" def __init__(self): pass - + @classmethod def get_name(cls): """ Returns Ext Resource Name """ @@ -56,7 +56,7 @@ class Qos(object): def get_namespace(cls): """ Returns Ext Resource Namespace """ return "http://docs.ciscocloud.com/api/ext/qos/v1.0" - + @classmethod def get_updated(cls): """ Returns Ext Resource update """ @@ -65,9 +65,9 @@ class Qos(object): @classmethod def get_resources(cls): """ Returns Ext Resources """ - parent_resource = dict(member_name="tenant", + parent_resource = dict(member_name="tenant", collection_name="extensions/csco/tenants") - + controller = QosController(QuantumManager.get_plugin()) return [extensions.ResourceExtension('qoss', controller, parent=parent_resource)] @@ -93,7 +93,7 @@ class QosController(common.QuantumController): def __init__(self, plugin): self._resource_name = 'qos' self._plugin = plugin - + def index(self, request, tenant_id): """ Returns a list of qos ids """ return self._items(request, tenant_id, is_detail=False) @@ -124,7 +124,7 @@ class QosController(common.QuantumController): #look for qos name in request try: req_params = \ - self._parse_request_params(request, + self._parse_request_params(request, self._qos_ops_param_list) except exc.HTTPError as exp: return faults.Fault(exp) @@ -140,7 +140,7 @@ class QosController(common.QuantumController): """ Updates the name for the qos with the given id """ try: req_params = \ - self._parse_request_params(request, + self._parse_request_params(request, self._qos_ops_param_list) except exc.HTTPError as exp: return faults.Fault(exp) From b0e199d0a92ce8a79b450b83b63f44c33d8f5d51 Mon Sep 17 00:00:00 2001 From: Shweta P Date: Fri, 26 Aug 2011 12:49:42 -0700 Subject: [PATCH 34/39] Dictionary key values changes in test_extension --- quantum/plugins/cisco/tests/unit/test_cisco_extension.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/quantum/plugins/cisco/tests/unit/test_cisco_extension.py b/quantum/plugins/cisco/tests/unit/test_cisco_extension.py index f4d958ee02..afebf545a7 100644 --- a/quantum/plugins/cisco/tests/unit/test_cisco_extension.py +++ b/quantum/plugins/cisco/tests/unit/test_cisco_extension.py @@ -326,7 +326,7 @@ class PortprofileExtensionTest(unittest.TestCase): else: net_name = self.network_name net_path = "/tenants/tt/networks" - net_data = {'network': {'net-name': '%s' % net_name}} + net_data = {'network': {'name': '%s' % net_name}} req_body = wsgi.Serializer().serialize(net_data, self.contenttype) network_req = self.create_request(net_path, req_body, self.contenttype, 'POST') @@ -334,7 +334,7 @@ class PortprofileExtensionTest(unittest.TestCase): network_data = wsgi.Serializer().deserialize(network_res.body, self.contenttype) LOG.debug("Creating network - END") - return network_data['networks']['network']['id'] + return network_data['network']['id'] def _create_port(self, network_id, port_state): @@ -342,7 +342,7 @@ class PortprofileExtensionTest(unittest.TestCase): LOG.debug("Creating port for network %s - START", network_id) port_path = "/tenants/tt/networks/%s/ports" % network_id - port_req_data = {'port': {'port-state': '%s' % port_state}} + port_req_data = {'port': {'state': '%s' % port_state}} req_body = wsgi.Serializer().serialize(port_req_data, self.contenttype) port_req = self.create_request(port_path, req_body, @@ -351,7 +351,7 @@ class PortprofileExtensionTest(unittest.TestCase): port_data = wsgi.Serializer().deserialize(port_res.body, self.contenttype) LOG.debug("Creating port for network - END") - return port_data['ports']['port']['id'] + return port_data['port']['id'] def test_associate_portprofile(self): From 274d14a3305fffcaad85c310179c7d6082c732d5 Mon Sep 17 00:00:00 2001 From: Shweta P Date: Sat, 27 Aug 2011 16:55:54 -0700 Subject: [PATCH 35/39] Adding Network and Port clean up functions for portprofile unit tests --- .../cisco/tests/unit/test_cisco_extension.py | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/quantum/plugins/cisco/tests/unit/test_cisco_extension.py b/quantum/plugins/cisco/tests/unit/test_cisco_extension.py index afebf545a7..55f9be6165 100644 --- a/quantum/plugins/cisco/tests/unit/test_cisco_extension.py +++ b/quantum/plugins/cisco/tests/unit/test_cisco_extension.py @@ -353,6 +353,25 @@ class PortprofileExtensionTest(unittest.TestCase): LOG.debug("Creating port for network - END") return port_data['port']['id'] + def _delete_port(self, network_id, port_id): + """ Delete port """ + LOG.debug("Deleting port for network %s - START", network_id) + port_path = "/tenants/tt/networks/%(network_id)s/ports/"\ + "%(port_id)s" % locals() + port_req = self.create_request(port_path, None, + self.contenttype, 'DELETE') + port_req.get_response(self.api) + LOG.debug("Deleting port for network - END") + + def _delete_network(self, network_id): + """ Delete network """ + LOG.debug("Deleting network %s - START", network_id) + network_path = "/tenants/tt/networks/%s" % network_id + network_req = self.create_request(network_path, None, + self.contenttype, 'DELETE') + network_req.get_response(self.api) + LOG.debug("Deleting network - END") + def test_associate_portprofile(self): """ Test associate portprofile""" @@ -388,6 +407,7 @@ class PortprofileExtensionTest(unittest.TestCase): delete_path = str(delete_path_temp) self.tear_down_associate_profile(delete_path, disassociate_path, req_assign_body) + self.tear_down_port_network(net_id, port_id) LOG.debug("test_associate_portprofile - END") def test_associate_portprofileDNE(self, portprofile_id='100'): @@ -445,8 +465,15 @@ class PortprofileExtensionTest(unittest.TestCase): resp_body['portprofiles']['portprofile']['id'] delete_path = str(delete_path_temp) self.tear_down_profile(delete_path) + self.tear_down_port_network(net_id, port_id) LOG.debug("test_disassociate_portprofile - END") + def tear_down_port_network(self, net_id, port_id): + """ Tear down port and network """ + + self._delete_port(net_id, port_id) + self._delete_network(net_id) + def tear_down_profile(self, delete_profile_path): """ Tear down profile""" From e87990643e34b2ebb8c614f248cb4c010d9abceb Mon Sep 17 00:00:00 2001 From: Sumit Naiksatam Date: Sat, 27 Aug 2011 22:00:23 -0700 Subject: [PATCH 36/39] bug fixes to handle multinic --- .../plugins/cisco/ucs/cisco_ucs_inventory.py | 105 ++++++++++++++---- 1 file changed, 83 insertions(+), 22 deletions(-) diff --git a/quantum/plugins/cisco/ucs/cisco_ucs_inventory.py b/quantum/plugins/cisco/ucs/cisco_ucs_inventory.py index 2a90824bb8..1a631717e3 100644 --- a/quantum/plugins/cisco/ucs/cisco_ucs_inventory.py +++ b/quantum/plugins/cisco/ucs/cisco_ucs_inventory.py @@ -28,6 +28,7 @@ from quantum.plugins.cisco.common import cisco_constants as const from quantum.plugins.cisco.common import cisco_credentials as cred from quantum.plugins.cisco.common import cisco_exceptions as cexc 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 ucs_db as udb from quantum.plugins.cisco.ucs \ import cisco_ucs_inventory_configuration as conf @@ -268,7 +269,68 @@ class UCSInventory(L2NetworkDeviceInventoryBase): tenant_id) return None - def _get_instance_port(self, tenant_id, instance_id, vif_id=None): + def _get_instance_port(self, tenant_id, instance_id, vif_id): + """ + Return the device name for a reserved interface + """ + found_blade_intf_data = None + for ucsm_ip in self._inventory_state.keys(): + ucsm = self._inventory_state[ucsm_ip] + for chassis_id in ucsm.keys(): + for blade_id in ucsm[chassis_id]: + blade_data = ucsm[chassis_id][blade_id] + blade_intf_data = blade_data[const.BLADE_INTF_DATA] + for blade_intf in blade_intf_data.keys(): + if blade_intf_data[blade_intf]\ + [const.BLADE_INTF_RESERVATION] == \ + const.BLADE_INTF_RESERVED and \ + blade_intf_data[blade_intf]\ + [const.TENANTID] == tenant_id and \ + blade_intf_data[blade_intf]\ + [const.INSTANCE_ID] == instance_id : + found_blade_intf_data = blade_intf_data + LOG.debug("Found blade %s associated with this" \ + " instance: %s" % \ + (blade_id, + instance_id)) + break + + if found_blade_intf_data: + blade_intf_data = found_blade_intf_data + for blade_intf in blade_intf_data.keys(): + if blade_intf_data[blade_intf]\ + [const.BLADE_INTF_RESERVATION] == \ + const.BLADE_INTF_RESERVED and \ + blade_intf_data[blade_intf]\ + [const.TENANTID] == tenant_id and \ + (not blade_intf_data[blade_intf][const.VIF_ID]): + blade_intf_data[blade_intf][const.VIF_ID] = \ + vif_id + blade_intf_data[blade_intf]\ + [const.INSTANCE_ID] = instance_id + port_binding = udb.get_portbinding_dn(blade_intf) + 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) + device_name = blade_intf_data[blade_intf]\ + [const.BLADE_INTF_RHEL_DEVICE_NAME] + profile_name = port_binding[const.PORTPROFILENAME] + dynamicnic_details = \ + {const.DEVICENAME: device_name, + const.UCSPROFILE: profile_name} + LOG.debug("Found reserved dynamic nic: %s" \ + "associated with port %s" % + (blade_intf_data[blade_intf], port_id)) + LOG.debug("Returning dynamic nic details: %s" % + dynamicnic_details) + return dynamicnic_details + + LOG.warn("Could not find a reserved dynamic nic for tenant: %s" % + tenant_id) + return None + + def _disassociate_vifid_from_port(self, tenant_id, port_id): """ Return the device name for a reserved interface """ @@ -284,28 +346,24 @@ class UCSInventory(L2NetworkDeviceInventoryBase): const.BLADE_INTF_RESERVED and \ blade_intf_data[blade_intf]\ [const.TENANTID] == tenant_id and \ - blade_intf_data[blade_intf]\ - [const.INSTANCE_ID] == instance_id: + blade_intf_data[blade_intf][const.PORTID] == \ + port_id: + vif_id = blade_intf_data[blade_intf][const.VIF_ID] blade_intf_data[blade_intf][const.VIF_ID] = \ - vif_id - port_binding = udb.get_portbinding_dn(blade_intf) - port_id = port_binding[const.PORTID] - udb.update_portbinding(port_id, - vif_id=vif_id) - device_name = blade_intf_data[blade_intf]\ - [const.BLADE_INTF_RHEL_DEVICE_NAME] - profile_name = port_binding[const.PORTPROFILENAME] - dynamicnic_details = \ - {const.DEVICENAME: device_name, - const.UCSPROFILE: profile_name} - LOG.debug("Found reserved dynamic nic: %s" \ - "associated with port %s" % - (blade_intf_data[blade_intf], port_id)) - LOG.debug("Returning dynamic nic details: %s" % - dynamicnic_details) - return dynamicnic_details - LOG.warn("Could not find a reserved dynamic nic for tenant: %s" % - tenant_id) + None + blade_intf_data[blade_intf][const.INSTANCE_ID] = \ + None + udb.update_portbinding(port_id, instance_id=None, + vif_id=None) + LOG.debug("Disassociated VIF-ID: %s " \ + "from port: %s" \ + "in UCS inventory state for blade: %s" % + (vif_id, port_id, + blade_intf_data[blade_intf])) + return + LOG.warn("Disassociating VIF-ID %s in UCS inventory failed. " \ + "Could not find a reserved dynamic nic for tenant: %s" % + (vif_id, tenant_id)) return None def reload_inventory(self): @@ -595,6 +653,9 @@ 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): From 7886ee494df1757d8c6ccbc5af106d68830ecc01 Mon Sep 17 00:00:00 2001 From: Sumit Naiksatam Date: Sat, 27 Aug 2011 22:55:08 -0700 Subject: [PATCH 37/39] Fixing the extensions URL to 1.0 and pep8 error. --- quantum/plugins/cisco/nova/quantum_aware_scheduler.py | 2 +- quantum/plugins/cisco/nova/vifdirect.py | 2 +- quantum/plugins/cisco/ucs/cisco_ucs_inventory.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/quantum/plugins/cisco/nova/quantum_aware_scheduler.py b/quantum/plugins/cisco/nova/quantum_aware_scheduler.py index b860ed2603..4394980dfa 100644 --- a/quantum/plugins/cisco/nova/quantum_aware_scheduler.py +++ b/quantum/plugins/cisco/nova/quantum_aware_scheduler.py @@ -35,7 +35,7 @@ flags.DEFINE_integer('quantum_port', 9696, HOST = FLAGS.quantum_host PORT = FLAGS.quantum_port USE_SSL = False -ACTION_PREFIX_EXT = '/v0.1' +ACTION_PREFIX_EXT = '/v1.0' ACTION_PREFIX_CSCO = ACTION_PREFIX_EXT + \ '/extensions/csco/tenants/{tenant_id}' TENANT_ID = 'nova' diff --git a/quantum/plugins/cisco/nova/vifdirect.py b/quantum/plugins/cisco/nova/vifdirect.py index 44842f8edd..015c9acebf 100644 --- a/quantum/plugins/cisco/nova/vifdirect.py +++ b/quantum/plugins/cisco/nova/vifdirect.py @@ -40,7 +40,7 @@ HOST = FLAGS.quantum_host PORT = FLAGS.quantum_port USE_SSL = False TENANT_ID = 'nova' -ACTION_PREFIX_EXT = '/v0.1' +ACTION_PREFIX_EXT = '/v1.0' ACTION_PREFIX_CSCO = ACTION_PREFIX_EXT + \ '/extensions/csco/tenants/{tenant_id}' TENANT_ID = 'nova' diff --git a/quantum/plugins/cisco/ucs/cisco_ucs_inventory.py b/quantum/plugins/cisco/ucs/cisco_ucs_inventory.py index 1a631717e3..1ed5e347d9 100644 --- a/quantum/plugins/cisco/ucs/cisco_ucs_inventory.py +++ b/quantum/plugins/cisco/ucs/cisco_ucs_inventory.py @@ -287,7 +287,7 @@ class UCSInventory(L2NetworkDeviceInventoryBase): blade_intf_data[blade_intf]\ [const.TENANTID] == tenant_id and \ blade_intf_data[blade_intf]\ - [const.INSTANCE_ID] == instance_id : + [const.INSTANCE_ID] == instance_id: found_blade_intf_data = blade_intf_data LOG.debug("Found blade %s associated with this" \ " instance: %s" % \ From f64f8d74a1f74323791bb65a5ed8103032ac5a74 Mon Sep 17 00:00:00 2001 From: rohitagarwalla Date: Sun, 28 Aug 2011 12:27:27 -0700 Subject: [PATCH 38/39] adding new api methods using just port_id --- quantum/plugins/cisco/db/api.py | 43 +++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/quantum/plugins/cisco/db/api.py b/quantum/plugins/cisco/db/api.py index db4e631a28..55bce235fb 100644 --- a/quantum/plugins/cisco/db/api.py +++ b/quantum/plugins/cisco/db/api.py @@ -252,3 +252,46 @@ def port_destroy(net_id, port_id): return port except exc.NoResultFound: raise q_exc.PortNotFound(port_id=port_id) + + +#methods using just port_id +def port_get_by_id(port_id): + session = get_session() + try: + return session.query(models.Port).\ + filter_by(uuid=port_id).one() + except exc.NoResultFound: + raise q_exc.PortNotFound(port_id=port_id) + + +def port_set_attachment_by_id(port_id, new_interface_id): + session = get_session() + port = port_get_by_id(port_id) + + if new_interface_id != "": + if port['interface_id']: + raise q_exc.PortInUse(port_id=port_id, + att_id=port['interface_id']) + + try: + port = session.query(models.Port).\ + filter_by(interface_id=new_interface_id).\ + one() + raise q_exc.AlreadyAttached(port_id=port_id, + att_id=new_interface_id, + att_port_id=port['uuid']) + except exc.NoResultFound: + pass + port.interface_id = new_interface_id + session.merge(port) + session.flush() + return port + + +def port_unset_attachment_by_id(port_id): + session = get_session() + port = port_get_by_id(port_id) + port.interface_id = None + session.merge(port) + session.flush() + return port From 5ea500ad330c73a8c15629d164f92c1fadaaaff0 Mon Sep 17 00:00:00 2001 From: Ying Liu Date: Tue, 30 Aug 2011 09:16:23 -0700 Subject: [PATCH 39/39] fix print statements in novatenant and portprofile --- extensions/novatenant.py | 2 -- extensions/portprofile.py | 2 -- 2 files changed, 4 deletions(-) diff --git a/extensions/novatenant.py b/extensions/novatenant.py index 4f083800e6..5309ce29ee 100644 --- a/extensions/novatenant.py +++ b/extensions/novatenant.py @@ -118,7 +118,6 @@ class NovatenantsController(common.QuantumController): #added for cisco's extension def schedule_host(self, request, tenant_id, id): content_type = request.best_match_content_type() - print "Content type:%s" % content_type try: req_params = \ @@ -139,7 +138,6 @@ class NovatenantsController(common.QuantumController): def associate_port(self, request, tenant_id, id): content_type = request.best_match_content_type() - print "Content type:%s" % content_type try: req_params = \ self._parse_request_params(request, diff --git a/extensions/portprofile.py b/extensions/portprofile.py index 8ecf65061a..4c0eda9296 100644 --- a/extensions/portprofile.py +++ b/extensions/portprofile.py @@ -175,7 +175,6 @@ class PortprofilesController(common.QuantumController): def associate_portprofile(self, request, tenant_id, id): """ associate a portprofile to the port """ content_type = request.best_match_content_type() - print "Content type:%s" % content_type try: req_params = \ @@ -198,7 +197,6 @@ class PortprofilesController(common.QuantumController): def disassociate_portprofile(self, request, tenant_id, id): """ Disassociate a portprofile from a port """ content_type = request.best_match_content_type() - print "Content type:%s" % content_type try: req_params = \ self._parse_request_params(request,