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
[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]
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
--- /dev/null
+[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>
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()
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"""
--- /dev/null
+"""
+# 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
--- /dev/null
+"""
+# 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.
+#
+"""
--- /dev/null
+"""
+# 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
+
LOG.getLogger(const.LOGGER_COMPONENT_NAME)
-class L2NetworkModel(L2NetworkModelBase):
+class L2NetworkSinlgeBlade(L2NetworkModelBase):
"""
Implements the L2NetworkModelBase
This implementation works with UCS and Nexus plugin,
"""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
+
--- /dev/null
+"""
+# 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.
+#
+"""
--- /dev/null
+"""
+# 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])
+
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)
--- /dev/null
+# 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()
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"
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,
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"""
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"]
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)
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"""
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"""
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)
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
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,
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,
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
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
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
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
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):
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,
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)
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
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,
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)
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]
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)
+