From: Sumit Naiksatam Date: Mon, 22 Aug 2011 10:34:48 +0000 (-0700) Subject: Refactoring of code to generalize inventory handling (enhancement). X-Git-Url: https://review.fuel-infra.org/gitweb?a=commitdiff_plain;h=294fe222ad43ee44bfe65b70dfac1ce8c639b4a6;p=openstack-build%2Fneutron-build.git Refactoring of code to generalize inventory handling (enhancement). --- diff --git a/quantum/plugins/cisco/common/cisco_constants.py b/quantum/plugins/cisco/common/cisco_constants.py index f2fa8805f..eb9af6873 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 8b4b476a0..de98ccb18 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 aea084781..a2d57e65a 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_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 _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_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_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 09bbfe9f7..7fcd65ba5 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): + 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 hostname of the blade with a reserved instance - for this tenant + Return the a dict with information of the blade + on which a dynamic vnic is available """ - 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 + 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_instance_port(self, tenant_id, instance_id, vif_id=None): + def get_port_details(self, args): """ - Return the device name for a reserved interface + Return the a dict with IP address of the blade + on which a dynamic vnic was reserved for this port """ - 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 + LOG.debug("get_port_details() called\n") + return self._get_blade_for_port(args) - def add_blade(self, ucsm_ip, chassis_id, blade_id): - """Add a blade to the inventory""" - # TODO (Sumit) - pass + 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