]> review.fuel-infra Code Review - openstack-build/neutron-build.git/commitdiff
Initial commit with lots of changes.
authorSumit Naiksatam <snaiksat@cisco.com>
Sat, 20 Aug 2011 03:07:28 +0000 (20:07 -0700)
committerSumit Naiksatam <snaiksat@cisco.com>
Sat, 20 Aug 2011 03:07:28 +0000 (20:07 -0700)
14 files changed:
quantum/plugins/cisco/common/cisco_constants.py
quantum/plugins/cisco/conf/l2network_plugin.ini
quantum/plugins/cisco/conf/ucs_inventory.ini [new file with mode: 0644]
quantum/plugins/cisco/l2network_plugin.py
quantum/plugins/cisco/l2network_segmentation_base.py [new file with mode: 0644]
quantum/plugins/cisco/models/__init__.py [new file with mode: 0644]
quantum/plugins/cisco/models/l2network_multi_blade.py [new file with mode: 0644]
quantum/plugins/cisco/models/l2network_single_blade.py [moved from quantum/plugins/cisco/l2network_model.py with 87% similarity]
quantum/plugins/cisco/segmentation/__init__.py [new file with mode: 0644]
quantum/plugins/cisco/segmentation/l2network_vlan_mgr.py [new file with mode: 0644]
quantum/plugins/cisco/ucs/cisco_ucs_configuration.py
quantum/plugins/cisco/ucs/cisco_ucs_inventory.py [new file with mode: 0644]
quantum/plugins/cisco/ucs/cisco_ucs_network_driver.py
quantum/plugins/cisco/ucs/cisco_ucs_plugin.py

index 67ba05d5811e2028f9b4fba5cff8402aa92d267e..02eb2d43110f0020fbc4e28746cd5f70cb029cd0 100644 (file)
@@ -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
index 3a740a9713c2e098ea895b711229866521d175a8..494279e79032e1f6e5ee03665753c6ae8c23a3d1 100644 (file)
@@ -1,6 +1,6 @@
 [VLANS]
-vlan_start=<put_vlan_id_range_start_here>
-vlan_end=<put_vlan_id_range_end_here>
+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 (file)
index 0000000..889609a
--- /dev/null
@@ -0,0 +1,24 @@
+[ucsm-1]
+ip_address = <put_ucsm_ip_address_here>
+[[chassis-1]]
+chassis_id = <put_the_chassis_id_here>
+[[[blade-1]]]
+blade_id = <put_blade_id_here>
+host_name = <put_hostname_here>
+[[[blade-2]]]
+blade_id = <put_blade_id_here>
+host_name = <put_hostname_here>
+[[[blade-3]]]
+blade_id = <put_blade_id_here>
+host_name = <put_hostname_here>
+
+[ucsm-2]
+ip_address = <put_ucsm_ip_address_here>
+[[chassis-1]]
+chassis_id = <put_the_chassis_id_here>
+[[[blade-1]]]
+blade_id = <put_blade_id_here>
+host_name = <put_hostname_here>
+[[[blade-2]]]
+blade_id = <put_blade_id_here>
+host_name = <put_hostname_here>
index 29fc3542429adcd17b3b4391801892e0a24e9a23..a4b30953e792af4c231b85b74aca10b03b6cabc8 100644 (file)
@@ -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 (file)
index 0000000..d7b4378
--- /dev/null
@@ -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 (file)
index 0000000..09b3fab
--- /dev/null
@@ -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 (file)
index 0000000..c5ba157
--- /dev/null
@@ -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
+
similarity index 87%
rename from quantum/plugins/cisco/l2network_model.py
rename to quantum/plugins/cisco/models/l2network_single_blade.py
index cdffa594e41763291db42619a36ec462e5287265..286f5c7ddefb95fec5762bac113f2fbd0630e016 100644 (file)
@@ -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 (file)
index 0000000..09b3fab
--- /dev/null
@@ -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 (file)
index 0000000..427ab69
--- /dev/null
@@ -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])
+
index 8c334815425068f27b278c131a73afec93fba475..a4fbec42b1b819a6b2132e8770611b5b3a6b7d7c 100644 (file)
@@ -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 (file)
index 0000000..a272c0a
--- /dev/null
@@ -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()
index faba86fcbda854fc9e431b039112cb2fc497e106..dfb7839f2e8ef3f0898427e7076f075277063544 100644 (file)
@@ -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 = "<configConfMos cookie=\"" + COOKIE_VALUE + \
 PROFILE_NAME + "\" status=\"deleted\"> </vnicProfile>" \
 "</pair> </inConfigs> </configConfMos>"
 
+GET_BLADE_INTERFACE_STATE = "<configScope cookie=\"" + COOKIE_VALUE + \
+        "\" dn=\"" + BLADE_DN_VALUE + "\" inClass=\"dcxVIf\" " +  \
+        "inHierarchical=\"false\" inRecursive=\"false\"> " + \
+        "<inFilter> </inFilter> </configScope>"
+
+GET_BLADE_INTERFACE = "<configResolveClass cookie=\"" + COOKIE_VALUE + \
+        "\" classId=\"vnicEther\"" + \
+        " inHierarchical=\"false\">" + \
+        " <inFilter> <eq class=\"vnicEther\" property=\"equipmentDn\"" + \
+        " value=\"sys/chassis-" + CHASSIS_VALUE +"/blade-" + \
+        BLADE_VALUE + "/adaptor-1/host-eth-?\"/> " +  \
+        "</inFilter> </configResolveClass>"
+
+# TODO (Sumit): Assumes "adaptor-1", check if this has to be discovered too
+GET_BLADE_INTERFACES = "<configResolveChildren cookie=\"" + \
+        COOKIE_VALUE + "\" inDn=\"sys/chassis-" + \
+        CHASSIS_VALUE + "/blade-" + BLADE_VALUE + \
+        "/adaptor-1\"" + \
+        " inHierarchical=\"false\"> <inFilter> </inFilter>" + \
+        " </configResolveChildren>"
+
 
 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 = "<aaaLogout inCookie=\"" + cookie + "\" />"
         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)
index f6b7daf5ffbe55691077fc6aa372b5667c2ff53e..d2f85fef740a8d0ebe6fe9ef751bd06ffdfe9260 100644 (file)
@@ -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)
+