#!/usr/bin/python
'''
Copyright 2014 Cisco Systems, Inc.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

'''

# Import the required modules here
from base64 import b64decode
import re
import os
import sys
from optparse import OptionParser
from UcsSdk import *
import csv
import shlex
import subprocess
import fcntl
from time import sleep
import pwd

from UcsSdk import Version
import random


# Check if user is running this as a CLI
# if true then the output is printed in user
# readable format else in Nagios format
if os.isatty(sys.stdin.fileno()):
    # CLI mode.
    END_DELIMITER = "\r\n"
else:
    # Nagios mode.
    END_DELIMITER = "<br>"

# Defining Attribute delimiter
ATTR_DELIMITER = ","

#Plugin version
UCSM_PLUGIN_VERSION = "0.9.4"

# Nagios State Variables
STATE_OK = 0
STATE_WARNING = 1
STATE_CRITICAL = 2
STATE_UNKNOWN = 3
STATE_DEPENDENT = 4

ERR_RETRY = "RETRY"

if not Version.__version__ >= '0.8.3':
    print 'This Nagios plugin does not support UCSM Python SDK version below 0.8.3.\n'\
            'Download the latest Cisco UCSM Python SDK from the following URL \n'\
            'https://communities.cisco.com/docs/DOC-37174'

    sys.exit(STATE_UNKNOWN)

class CheckForCommentOrBlank:
    '''
    Overriding the Csv Class for checking configuration file for 
    hash(#) and spaces and will ignore those lines
    '''
    def __init__(self, fp):
        self.fp = fp

    def __iter__(self):
        return self

    def next(self):
        line = self.fp.next()
        if not line.strip() or line.startswith('#'):
            return self.next()
        return line

    def close(self):
        self.fp.close()


def execute_unix_cmd(command):
    args = shlex.split(command.strip('"'))
    p = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    cmd_output = p.communicate()
    cmd_return_code = p.wait()
    return (cmd_return_code, cmd_output)


def convert_to_html(text):
    html_convert = {"<": "&lt;", ">": "&gt;", "\"": "&quot;", "&": "&amp;"}
    html_list = [char for char in text]
    html_converted_txt = []
    for char in html_list:
        if char in html_convert:
            char = html_convert[char]
            html_converted_txt.append(char)
        else:
            html_converted_txt.append(char)
    html_escaped_text = "".join(html_converted_txt)
    return html_escaped_text


def read_properties(filename):
    '''
    Reads a given properties file with each line of the format key=value.
    Returns a dictionary containing the pairs.
    :param filename: The name of the file to be read
    '''
    # Check if configuration file exists or not
    if os.path.exists(filename) is False:
        raise Exception("UCS Plugin Configuration file '%s' not found. "
                        % filename)
    try:
        file_type = execute_unix_cmd("file " + filename)
        # cisco_imc_nagios.cfg: ASCII English text
        if not (file_type[0] == 0 and re.search("ASCII", file_type[1][0])
                is not None):
            raise Exception('Error occurred while checking plugin '
                            'configuration file format.'
                            'File may contain invalid characters.')
    except Exception, cfg_err:
        raise Exception(str(cfg_err))
    result = dict()
    cfg_file = CheckForCommentOrBlank(open(filename, 'rb'))
    reader = csv.reader(cfg_file, delimiter='=', escapechar='\\',
                        quoting=csv.QUOTE_NONE)
    for row in reader:
        if len(row) != 2:
            raise Exception('Check if configuration properties are in the'
                            ' format PROPERTY_NAME = VALUE.' +
                             END_DELIMITER + 'Also check the VALUE should be in a single line.')
        result[row[0].strip()] = row[1].strip()
    cfg_file.close()
    return result


def word_to_lower(word):
    '''
    Method used for converting class and attributes passed
    by end user to the format expected by pythonSDK
    :param word:A string containing class or attribute
    '''
    return (word[0].lower() + word[1:])


def word_to_upper(word):
    '''
    Method used for converting class and attributes passed
    by end user to the format expected by pythonSDK
    :param word: A string containing class or attribute
    '''
    return (word[0].upper() + word[1:])

NAGIOS_LIB_EXEC = os.path.dirname(os.path.realpath(__file__))
CONFIGURATION_FILE = NAGIOS_LIB_EXEC + os.sep + 'cisco_ucs_nagios.cfg'
try:
    PLUGIN_CFG_DICT = read_properties(CONFIGURATION_FILE)
except Exception, err:
    print "Error while trying to read plugin configuration file '%s' ."  % CONFIGURATION_FILE
    print str(err)
    sys.exit(STATE_UNKNOWN)
try:
    class_mo_list = PLUGIN_CFG_DICT['CLASS_FILTER_LIST']
    fault_mo_list_temp = class_mo_list.split(",")
    fault_mo_list = []
    for class_id in fault_mo_list_temp:
        class_id = class_id.strip()
        fault_mo_list.append(word_to_upper(class_id))
except Exception, err:
    fault_mo_list = []

# Class for creating objects and
# storing child objects and faults
# so that hierarchy can be maintained
class FaultClass:
    def __init__(self, mo, pdn):
        self.mo = mo
        self.dn = pdn + "/" + mo.Rn
        self.child = []
        self.faults = []

# A recursive method for creating the custom managed objects
# and maintaining the mo hierarchy and faults associated with that mo.
def create_fault_object(fault_object):
    for cmo in fault_object.mo.GetChild():
        if cmo.classId == "FaultInst":
            fault_object.faults.append(cmo)
        if fault_mo_list:
            if cmo.classId in fault_mo_list:
                fault_object.child.append(create_fault_object(FaultClass(cmo, fault_object.dn)))
            else:
                continue
        else:
            fault_object.child.append(create_fault_object(FaultClass(cmo, fault_object.dn)))
    return fault_object

def generate_fault_report(mo_list, ucs_object,verbose=False):
    return_status = STATE_OK
    return_string = END_DELIMITER
    fault_detail = ""
    for mo in mo_list:
        fault_descr = ""
        if fault_mo_list:
            if mo.classId in fault_mo_list:
                fault_object = FaultClass(mo, os.path.dirname(mo.Dn))
            else:
                continue
        else:
            fault_object = FaultClass(mo, os.path.dirname(mo.Dn))
        for cmo in mo.GetChild():
            if cmo.classId == "FaultInst":
                fault_object.faults.append(cmo)
            if fault_mo_list:
                if cmo.classId in fault_mo_list:
                    fault_object.child.append(create_fault_object(FaultClass(cmo, fault_object.dn)))
                else:
                    continue
            else:
                fault_object.child.append(create_fault_object(FaultClass(cmo, fault_object.dn)))

        return_power_state = get_server_health_state(ucs_object,mo.Dn)
        if return_power_state != "" and return_power_state !=0 :
            fault_descr += mo.classId + " (" + mo.Dn + ") - " + get_service_status_text(return_power_state) +\
                 " Operational Health of Blade is not OK." + END_DELIMITER 
            if return_status <= return_power_state:
                return_status = return_power_state
        
        return_string +=fault_descr
        if fault_object is not None:

            (overall_state_flag, main_str,fault_info) = print_fault_object(fault_object, verbose)
            if return_status < overall_state_flag:
                return_status = overall_state_flag
            return_string += main_str
            fault_detail +=fault_info
            if main_str.strip() == "" and fault_descr.strip() == "" and args_object.only_faults:
                inv_details = get_inv_details(ucs_object, mo.Dn)
                return_string += mo.Dn + " -" + get_service_status_text(overall_state_flag) + inv_details + END_DELIMITER
        else:
            if fault_descr.strip() == "" and args_object.only_faults:
                inv_details = get_inv_details(ucs_object, mo.Dn)
                return_string += mo.Dn + " -" + get_service_status_text(overall_state_flag) + inv_details + END_DELIMITER
    #End of For Loop

    if fault_mo_list:
        msg_str = END_DELIMITER + END_DELIMITER + "*** Hierarchical Fault Filtering ON ***" + END_DELIMITER + " Please Check CLASS_FILTER_LIST property."
    else:
        msg_str = END_DELIMITER + END_DELIMITER + "*** Hierarchical Fault Filtering OFF ***"
    if args_object.only_faults:
        fault_detail += msg_str
        return {'Overall Health Status': [return_status, fault_detail, return_string]}
    else:
        return_string += msg_str
        return {'Overall Health Status': [return_status, "", return_string]}

def print_fault_object(fault_object, verbose_flag, str_prefix_cnt=0,
                       overall_state=STATE_OK, overall_status_str="",fault_info=""):
    str_prefix = " "
    indent = str_prefix * str_prefix_cnt
    head_fault_str = fault_object.mo.classId + " (" + fault_object.dn + ")"
    return_state = overall_state
    current_return_state = STATE_OK
    if len(fault_object.faults) > 0:
        for fault in fault_object.faults:
            if check_skip_fault(fault,fault_object.dn):
                continue
            fault_info += "\n ==== Fault Detail ==== " + END_DELIMITER
            fault_info += get_fault_detail_text(fault.classId, [fault],fault_object.dn)
            if re.search(PLUGIN_CFG_DICT['NAGIOS_CRITICAL'], fault.Severity) \
               is not None:
                current_return_state = STATE_CRITICAL
                fault_descr = fault.Descr
            elif re.search(PLUGIN_CFG_DICT['NAGIOS_WARNING'], fault.Severity) \
                    is not None:
                    current_return_state = STATE_WARNING
                    fault_descr = fault.Descr
            else:
                current_return_state = STATE_OK
                fault_descr = ""
                continue
            if return_state < current_return_state:
                return_state = current_return_state
            if verbose_flag:
                overall_status_str += indent + head_fault_str + " - " + \
                    get_service_status_text(current_return_state) + \
                    fault_descr + END_DELIMITER
            else:
                if current_return_state == STATE_CRITICAL:
                    if overall_state == STATE_CRITICAL:
                        # Append to the existing str
                        overall_status_str += indent + head_fault_str + " - " +\
                            get_service_status_text(current_return_state) + \
                            fault_descr + END_DELIMITER
                    else:
                        # New string
                        overall_status_str = indent + head_fault_str + " - " +\
                            get_service_status_text(current_return_state) + \
                            fault_descr + END_DELIMITER
                elif current_return_state == STATE_WARNING and \
                        (overall_state == STATE_WARNING or overall_state ==
                         STATE_OK):
                        overall_status_str += indent + head_fault_str + " - " + \
                            get_service_status_text(current_return_state) + \
                            fault_descr + END_DELIMITER
                else:
                    pass
    else:
        if verbose_flag:
            overall_status_str += indent + head_fault_str +\
                "- OK " + END_DELIMITER

    for fo in fault_object.child:
        str_prefix_cnt += 2
        (return_state, overall_status_str,fault_info) = print_fault_object(fo, verbose_flag,
                                                                str_prefix_cnt,
                                                                return_state,
                                                                overall_status_str,fault_info)
        str_prefix_cnt -= 2

    return (return_state, overall_status_str,fault_info)
    # print faultInfo

def get_fault_list_for_dn(dn,filter_str,hierarchical_flag=False):
    fmo_list = []
    in_filter_fault = FilterFilter()
    in_filter_fault.AddChild(get_wcard_filter("FaultInst", filter_str))
    fault_mo_list_temp = ucs_object.ConfigResolveClass("FaultInst",
                                                       inHierarchical=hierarchical_flag,
                                                       inFilter=in_filter_fault)
    if fault_mo_list_temp and fault_mo_list_temp.OutConfigs is not None:
        fmo_list = fault_mo_list_temp.OutConfigs.GetChild()
    return fmo_list

# Function for checking if we need to skip the given fault
def check_skip_fault(fault_mo,fault_parent_dn=""):
    try:
        fault_skip_list = PLUGIN_CFG_DICT['SKIP_FAULT_LIST'].split(",")
    except KeyError:
        return False
    for skip_fault in fault_skip_list:
        if skip_fault.strip() == "":
            continue
        attr_name = word_to_upper(skip_fault.split(":")[0].strip())
        attr_value = skip_fault.split(":",1)[1].strip()
        if fault_mo.getattr(attr_name) == None and attr_name.lower() == "dn":
            if fault_parent_dn.strip() != "":
                dn = fault_parent_dn.strip() + "/" + fault_mo.getattr("Rn")
                if dn.lower() == str(attr_value).lower():
                    return True
        elif fault_mo.getattr(attr_name) == None:
            continue
        else:
            if fault_mo.getattr(attr_name).lower() == str(attr_value).lower():
                return True
    return False

def acquire_lock(ucshost):
    i = 0
    try:
        while_count = int(PLUGIN_CFG_DICT['LOCK_RETRY_COUNT'].strip())
    except:
        while_count = 60
    try:
        sleep_time = float(PLUGIN_CFG_DICT['LOCK_RETRY_INTERVAL'].strip())
    except:
        sleep_time = random.random()
    try:
        tmp_path = PLUGIN_CFG_DICT['CISCO_TEMP_PATH'].strip()
    except:
        tmp_path = "/tmp/cisco_ucs_tmp"

    # if os.path.exists(tmp_path):
    username = pwd.getpwuid(os.geteuid()).pw_name
    lock_file = tmp_path + "/" + ucshost + '_' + username + ".lock_ucsm"
    fd_lock = open(lock_file, 'w')
    while i < while_count:
        try:
            # Converted to a blocking call and will 
            # let Nagios time out this waiting process
            #fcntl.flock(fd_lock, fcntl.LOCK_EX|fcntl.LOCK_NB)
            # right now we are doing a blocking and if required 
            # we may use the same code for timeout implementation
            fcntl.flock(fd_lock, fcntl.LOCK_EX)
            break
        except Exception,err:
            if args_object.debug: 
                print "Unable to get lock . Retrying for ",str(i)
            sleep(sleep_time)
            i += 1
    if i == while_count:
        fd_lock = None
    return fd_lock


def release_lock(fd_lock):
    fcntl.flock(fd_lock, fcntl.LOCK_UN)
    fd_lock.close()


def get_data_from_file(cookie_file):
    fd = open(cookie_file, 'r')
    try:
        file_data = fd.readlines()
        fd.close()
    except Exception, err:
        if args_object.debug:
            print str(err)
        fd.close()
        raise Exception(str(err))
    return file_data


def write_data_to_file(cookie_file, cookie):
    fd = open(cookie_file,'w')
    try:
        os.chmod(cookie_file, 0600)
        fd.write(cookie)
        fd.flush()
        fd.close()
    except Exception, err:
        if args_object.debug:
            print str(err)
        print str(err)
        fd.close()


def is_cookie_valid(ucs_handle):
    resp = ucs_handle.AaaKeepAlive()
    if resp.errorCode != 0:
        return False
    else:
        return True


def login_ucs(ucshost, user, password, no_ssl=False, port=None, debug=None, proxy=None):
    # Method UCS Login
    ucs_handle = UcsHandle()
    if debug:
        ucs_handle.SetDumpXml()
    username = pwd.getpwuid(os.geteuid()).pw_name

    try:
        tmp_path = PLUGIN_CFG_DICT['CISCO_TEMP_PATH']
    except:
        tmp_path = "/tmp/cisco_ucs_tmp"
    if not os.path.exists(tmp_path):
        try:
            os.makedirs(tmp_path)
            os.chmod(tmp_path, 0777)
        except Exception, err:
            print str(err)
            return None
    cookie_file = tmp_path + "/" + ucshost + '_' + username + '_' + user +".txt"
    fd_lock = acquire_lock(ucshost)
    if fd_lock is not None:
        if os.path.isfile(cookie_file):
            try:
                file_data = get_data_from_file(cookie_file)
            except Exception, err:
                if debug:
                    print "Error occurred for an existing cookie file. \n", str(err)
                    print "Removing the cookie file now : ", str(cookie_file)
                os.remove(cookie_file)
                return ERR_RETRY
            cookie = file_data[0].strip()
            ucs_handle._cookie = cookie
            ucs_handle._username = user
            ucs_handle._password = password
            if port is None:
                if no_ssl:
                    ucs_handle._port = 80
                else:
                    ucs_handle._port = 443
            else:
                ucs_handle._port = int(port)
            ucs_handle._ucs = ucshost
            ucs_handle._name = ucshost
            ucs_handle._noSsl = no_ssl
            ucs_handle._proxy = proxy
            # check for the validity of the cookie
            if not is_cookie_valid(ucs_handle):
                try:
                    ucs_handle.Logout()
                except Exception, err:
                    if debug:
                        print "Error occurred while trying to logout as the cookie was not valid. \n", str(err)
                    pass
                ucs_handle.Login(ucshost, user, password, noSsl=no_ssl,
                                 port=port, dumpXml=debug, proxy=proxy,
                                 autoRefresh=False)
                write_data_to_file(cookie_file, ucs_handle._cookie)
        else:
            # Make a login call and store the details in the file
            ucs_handle.Login(ucshost, user, password, noSsl=no_ssl, port=port,
                             dumpXml=debug, proxy=proxy, autoRefresh=False)
            write_data_to_file(cookie_file, ucs_handle._cookie)
        release_lock(fd_lock)
    else:
        ucs_handle = None
    return ucs_handle




def get_fault_details(ucs_object, query, in_filter, hierarchical_flag=False, v=False, only_faults=False):
    '''
    Function for fetching the Fault details and also check for
    the highest severity fault status
    :param ucs_object: A valid UCS
    :param query: class or dn
    :param in_filter: filter to be applied on the query
    :param hierarchical_flag: Is query to be done for a hierarchy True or False
    :param v: verbose true or false
    :param only_faults: search only the fault information True or False
    :return: A dict that contains the following in a list with key as dn
        - nagios state
        - faultInfo in case the fault is found on that class or dn ,  else None
        - faultDescr in case the fault is found on that class or dn
    '''
    fmos_dict = dict()
    fmo_list = []
    if hierarchical_flag:
    # for DN
        if check_for_dn(query):
            crdn_resp = ucs_object.ConfigResolveDn(query, inHierarchical=hierarchical_flag)
            if crdn_resp.errorCode != 0:
                raise UcsException(crdn_resp.errorCode, crdn_resp.errorDescr)
            pmo_list = crdn_resp.OutConfig.GetChild()
            if not pmo_list:
                fmos_dict[query] = [STATE_WARNING, "Check if the Dn '%s' exists on the given UCS host." % (query), None]
                return fmos_dict
        else:
            # The variable contain class name
            crc_resp = ucs_object.ConfigResolveClass(classId=query, inFilter=in_filter, inHierarchical=hierarchical_flag)
            if crc_resp.errorCode != 0:
                raise UcsException(crc_resp.errorCode, crc_resp.errorDescr)
            if not crc_resp.OutConfigs:
                fmos_dict[query] = [STATE_WARNING, "Check if the class '%s' exists on the given UCS host." % (query) + END_DELIMITER +\
                'In case you have provided a filter then please check if the attribute that you want' + END_DELIMITER + \
                'to filter exists. Else there is no data for the provided filter value.', None]
                return fmos_dict
            pmo_list = crc_resp.OutConfigs.GetChild()
            if not pmo_list:
                fmos_dict[query] = [STATE_WARNING, "Check if the class '%s' exists on the given UCS host." % (query)+ END_DELIMITER +\
                'In case you have provided a filter then please check if the attribute that you want'+ END_DELIMITER +\
                'to filter exists. Else there is no data for the provided filter value.', None]
                return fmos_dict
        fmos_dict = generate_fault_report(pmo_list, ucs_object,v)
        return fmos_dict
    if check_for_dn(query) or only_attr_flag:
        # for DN
        if hierarchical_flag:
            filter_str = "dn:" + query + "/"
        else:
            filter_str = "dn:" + query + "/fault*"
        # In this case get the configResolveClass with filters
        fmo_list = get_fault_list_for_dn(query, filter_str)
        fmos_dict[query] = fmo_list
    else:
        # For Class
        crdn_resp = ucs_object.ConfigFindDnsByClassId(query, in_filter)
        if crdn_resp.errorCode != 0:
            raise UcsException(crdn_resp.errorCode, crdn_resp.errorDescr)
        if crdn_resp.OutDns is None:
            fmos_dict[query] = [STATE_WARNING,
                               "Check if the class '%s' exists on the given UCS host." % (query) +  END_DELIMITER + \
                               'Else there is no data for the provided class or filter value.', None]
            return fmos_dict
        dn_list = crdn_resp.OutDns.GetChild()
        if not dn_list:
            fmos_dict[query] = [STATE_WARNING,
                               "Check if the class '%s' exists on the given UCS host." % (query) +  END_DELIMITER + \
                               'Else there is no data for the provided class or filter value.', None]
            return fmos_dict
        else:
            if args_object.filter is not None:
                str_filter = args_object.filter.strip().split(":")
                filter_prop = str_filter[0].strip()
                filter_value = str_filter[1].strip()
                re_exp = r'(\s|^|$|/)'
            found_dn = False
            for dn in dn_list:
                dn_name = dn.Value
                if args_object.filter is not None:
                    # Check for cases like dn_name="sys/chassis-10" but filter was for "sys/chassis-1"
                    if filter_prop == 'dn' and not bool(re.match(re_exp + filter_value + re_exp, dn_name.strip() , flags=re.IGNORECASE))  :
                        continue
                if hierarchical_flag:
                    filter_str = "dn:" + dn_name + "/"
                else:
                    filter_str = "dn:" + dn_name + "/fault*"
                fmo_list = get_fault_list_for_dn(dn_name, filter_str)
                fmos_dict[dn_name] = fmo_list
                found_dn = True
            if not found_dn:
                fmos_dict[query] = [STATE_WARNING,
                               "Check if the class '%s' exists on the given UCS host." % (query) +  END_DELIMITER + \
                               'Else there is no data for the provided class or filter value.', None]
                return fmos_dict
    count = 0
    for key in fmos_dict.iterkeys():
        fault_info = ""
        fmo_list = fmos_dict[key]
        return_state = STATE_OK
        current_return_state = STATE_OK
        fault_descr = ""
        stat_details = ""
        return_power_state = get_server_health_state(ucs_object,key)
        if fmo_list:
            # WriteObject(fmo_list)
            for fault_mo in fmo_list:
                if check_skip_fault(fault_mo):
                    continue
                count = count + 1
                fault_info += "\n ==== Fault # " + str(count) + " ==== " + END_DELIMITER
                # Mapping of UCS Severity to Nagios as follows
                # Critical,Major - Critical
                # Minor,Warning - Warning
                # Others - OK
                if re.search(PLUGIN_CFG_DICT['NAGIOS_CRITICAL'],
                             fault_mo.Severity) is not None:
                    current_return_state = STATE_CRITICAL
                    fault_descr += END_DELIMITER + get_service_status_text(current_return_state) +\
                        os.path.dirname(fault_mo.Dn) + "-" + fault_mo.Descr
                elif re.search(PLUGIN_CFG_DICT['NAGIOS_WARNING'], 
                               fault_mo.Severity) is not None:
                    current_return_state = STATE_WARNING
                    fault_descr += END_DELIMITER + get_service_status_text(current_return_state) +\
                        os.path.dirname(fault_mo.Dn) + "-" + fault_mo.Descr
                else:
                    current_return_state = STATE_OK
                    fault_descr += END_DELIMITER + get_service_status_text(current_return_state) +\
                        os.path.dirname(fault_mo.Dn) + "-" + fault_mo.Descr
                # fault_info+=get_all_mo_attributes(fault_mo)
                fault_info += get_fault_detail_text(fault_mo.classId, [fault_mo])
                if return_state <= current_return_state:
                    return_state = current_return_state
            # For loop ends
            if return_power_state != "" and return_power_state !=0 :
                fault_descr += END_DELIMITER + get_service_status_text(return_power_state) +\
                     key + " Operational Health of Blade is not OK." 
                if return_state <= return_power_state:
                    return_state = return_power_state
            if fault_descr == "":
                fault_descr = None
                inv_details = get_inv_details(ucs_object, key)
                if not only_faults:
                    stat_details = get_stat_details(ucs_object, key)
                if stat_details.strip() != "":
                    inv_details = inv_details + "|" + stat_details.strip()
                fmos_dict[key] = [STATE_OK, None, inv_details]
            else:
                if not only_faults:
                    stat_details = get_stat_details(ucs_object, key)
                if stat_details.strip() != "":
                    fault_descr = fault_descr + "|" + stat_details.strip()
                fmos_dict[key] = [return_state, fault_info, fault_descr]
        else:
    	    if return_power_state != "" and return_power_state !=0:
                if not only_faults:
                    stat_details = get_stat_details(ucs_object, key)
	        fault_descr = "Operational Health of Blade is not OK."
                if stat_details.strip() != "":
                    fault_descr = fault_descr + "|" + stat_details.strip()
	    	fmos_dict[key] = [return_power_state, None, fault_descr]
	    else:
                inv_details = get_inv_details(ucs_object, key)
                if not only_faults:
                    stat_details = get_stat_details(ucs_object, key)
                if not stat_details:
                    stat_details = ""
                if stat_details.strip() != "":
                    inv_details = inv_details + "|" + stat_details.strip()
                if inv_details is None:
                    fmos_dict[key] = [STATE_WARNING, "Check if the Dn '%s' exists on the given UCS host." % (key), None]
                else:
                    fmos_dict[key] = [STATE_OK, None, inv_details]
    return fmos_dict

# Method for fetching all the attributes for a
# given MO
def get_all_mo_attributes(mo):
    info_string = ""
    tabsize = 8
    for prop in vars(mo).keys():
        if (prop in ['class_id', 'XtraProperty', 'handle', 'propMoMeta',
                     'dirtyMask', 'child', 'Lc', 'ChildAction', 'Rn']):
            continue
        val = mo.getattr(prop)
        info_string += str(prop) + "  " + ':' + "  " + str(val) + ATTR_DELIMITER
        if vars(mo).has_key('XtraProperty'):
            for xtra_prop in vars(mo)['XtraProperty'].keys():
                info_string += str(xtra_prop).ljust(tabsize * 4) + ':' +\
                 str(vars(mo)['XtraProperty'][xtra_prop]) + ATTR_DELIMITER
    return info_string.strip(ATTR_DELIMITER)

# Method to find Blade health State.
def get_server_health_state(ucs_object,query):
    return_state = ""
    try:
        power_critical_list = PLUGIN_CFG_DICT['POW_STATE_CRITICAL'].split("|")
        critical_list = []
        for state in power_critical_list:
            critical_list.append((state.strip().lower()))
    except:
        critical_list = []

    try:
        power_warning_list = PLUGIN_CFG_DICT['POW_STATE_WARNING'].split("|")
        warning_list = []
        for state in power_warning_list:
            warning_list.append((state.strip().lower()))
    except:
        warning_list = []

    try:
        power_healthy_list = PLUGIN_CFG_DICT['POW_STATE_HEALTHY'].split("|")
        healthy_list = []
        for state in power_healthy_list:
            healthy_list.append((state.strip().lower()))
    except:
        healthy_list = []
    try:
        mo_obj = ucs_object.GetManagedObject(None, None, {'Dn': query})
        if not mo_obj:
            return_state = ""
        elif (mo_obj[0].Association).lower() == "associated":
            if (mo_obj[0].OperPower).lower() in critical_list:
                return_state = STATE_CRITICAL
            elif (mo_obj[0].OperPower).lower() in warning_list:
                return_state = STATE_WARNING 
            elif (mo_obj[0].OperPower).lower() in healthy_list:
                return_state = STATE_OK
            else:
                return_state = STATE_UNKNOWN
        return return_state
    except:
        return return_state


# Method for converting Nagios status to a string
def get_service_status_text(fault_type):
    if fault_type == 0:
        return_text = "OK - "
    elif fault_type == 1:
        return_text = "WARNING - "
    elif fault_type == 2:
        return_text = "CRITICAL - "
    else:
        return_text = "UNKNOWN - "
    return return_text


# Function to fetch the inventory details for the given details"
def get_inv_details(ucs_object, query):
    return_text = ""
    mo_obj = ucs_object.GetManagedObject(None, None, {'Dn': query})
    if not mo_obj:
            # print "DN was " + query
        return_text = None
    else:
        return_text = get_inv_detail_text(mo_obj[0].classId, mo_obj)
    return return_text

# Function to fetch the inventory details for the given details"
def get_stat_details(ucs_object, query):
    return_text = ""
    mo_obj = ucs_object.GetManagedObject(None, None, {'Dn': query})
    if not mo_obj:
        return_text = None
    else:
        return_text = get_stat_detail_text(mo_obj[0].classId, mo_obj)
    return return_text


# Proxy method for fetching the inventory details or attributes
# as defined by end user in the configuration file.
def get_inv_detail_text(switch_type, mo):
    return get_detail_text(switch_type, mo, 'INV')

# [For Future Use] Proxy Method used for fetching the performance
# attribute as defined by the end use in the configuration file.
def get_stat_detail_text(switch_type, mo):
    return get_detail_text(switch_type, mo, 'STAT')

def get_fault_detail_text(switch_type, mo,parent_dn = ""):
    return get_detail_text(switch_type, mo, 'FAULT',parent_dn)

# Method for getting the inventory or stats/performance data.
def get_detail_text(switch_type, mo_object, for_type='INV',parent_dn=""):
    property_avaliable_flag = False
    if for_type == 'INV':
        key_val_seprator = ' : '
        end_delimiter = ATTR_DELIMITER
        switch_type = "Inv_" + switch_type
    elif for_type == 'FAULT':
        key_val_seprator = ' : '
        end_delimiter = END_DELIMITER
    else:
        key_val_seprator = '='
        end_delimiter = ' '
        switch_type = "Stats_" + switch_type
    return_text = ""
    if switch_type in PLUGIN_CFG_DICT:
        property_avaliable_flag = True
    else:
        switch_type_class = switch_type.split("_")[1]
        switch_type_class_lower = word_to_lower(switch_type_class)
        if for_type == 'INV':
            switch_type = "Inv_" + switch_type_class_lower
        elif for_type == 'FAULT':
            switch_type = switch_type_class_lower
        else:
            switch_type = "Stats_" + switch_type_class_lower

        if switch_type in PLUGIN_CFG_DICT:
            property_avaliable_flag = True

    if property_avaliable_flag:
        try:
            attr_list = PLUGIN_CFG_DICT[switch_type].split(",")
        except:
            attr_list = ""
        for mo in mo_object:
            for attr in attr_list:
                attr = attr.strip()
                if for_type == "STAT":
                    return_text += get_stats_detail_txt(switch_type, mo_object,attr,key_val_seprator) + end_delimiter
                else :
                    attr_given_name = None
                    if re.search(':', attr):
                        attr_temp = attr.split(':')
                        attr = attr_temp[0]
                        attr_given_name = attr_temp[1]
                    try:
                        value = mo.getattr(word_to_upper(attr))
                    except:
                        value = "NA"
                    if value == None and word_to_upper(attr) == "Dn" and parent_dn.strip() != "":
                        value = parent_dn.strip() + "/" + mo.Rn
                    if value is None:
                        value = "NA"
                    if attr_given_name is not None:
                        return_text += attr_given_name + key_val_seprator + value + end_delimiter
                    else:
                        return_text += attr + key_val_seprator + value + end_delimiter
    else:
        if for_type != 'STAT':
            try:
                for mo in mo_object:
                    return_text = get_all_mo_attributes(mo)
            except Exception:
                value = "NA"
    return return_text.strip(end_delimiter)

def get_stats_detail_txt(switch_type, mo_object,attribute,key_val_seprator):
    uom_list = []
    try:
        uom_extract_list = PLUGIN_CFG_DICT['STATS_UOM_LIST'].split(",")
        for uom in uom_extract_list:
            uom_list.append(uom.strip()) 
    except:
        pass
    return_text = ""
    end_delimiter = ";"
    attr_list = attribute.split(";",6)
    if len(attr_list) > 6:
       attr_list.pop()
    for mo in mo_object:
        counter = 0
        for attr in attr_list:
            if attr == "":
                value = "" 
            else :
                attr_given_name = None
                if re.search(':', attr):
                    attr_temp = attr.split(':')
                    attr = attr_temp[0]
                    attr_given_name = attr_temp[1]
                try:
                    value = mo.getattr(word_to_upper(attr))
                except:
                    value = ""

            if value is None:
                value = ""
            if counter == 0 and value == "":
                return return_text
            elif counter == 0 and value != "":
                if attr_given_name is not None:
                    return_text += attr_given_name + key_val_seprator + value
                else:
                    return_text += attr + key_val_seprator + value
            elif counter == 1:
                if attr in uom_list:
                    return_text += attr + end_delimiter
                else:
                    return_text += end_delimiter
            else:
                try:
                    test = int(attr)
                    value = attr
                except:
                    pass
                return_text += value + end_delimiter
            counter += 1
    return return_text


# # Have to use this due to bug in python arg parser.
# As we need to support python 2.4 hence we are using this option parser
def check_for_valid_inputs(input_val):
    input_var_list = ["-H", "--host", "-n", "--port", "--no_ssl", "-u",
                      "--user", "-p", "--password", "--pass_enc", "-t",
                      "--type", "-q", "--query", "-a", "--attribute",
                      "-w", "--warn", "-r", "--regex", "--proxy", "-v",
                      "--verbose", "--debug",
                      "--inHierarchical"]
    check_flag = False
    if input_val is None or input_val.strip() == "":
        check_flag = True
    else:
        for var in input_var_list:
            if input_val.strip() == var:
                check_flag = True
                break
    return check_flag

# Method for getting attribute or property values for a given MO
# this method also handles the user given name for the attributes
def get_attribute_value(attr, mo):
    attr_given_name = None
    try:
        if re.search(':', attr):
            attr_temp_list = attr.split(':')
            attr = attr_temp_list[0].strip()
            attr_given_name = attr_temp_list[1].strip()
        attr_value = mo.getattr(word_to_upper(attr))
    except Exception, err:
        if err.__class__ == AttributeError:
            raise AttributeError("Unable to find the requested attribute '%s' in the query response." % (attr))
    return [attr_value, attr_given_name]


def get_wcard_filter(classId, filter_string):
    str_filter = filter_string.strip().split(":")
    wcard_filter = WcardFilter()
    wcard_filter.Class = word_to_lower(classId.strip())
    wcard_filter.Property = str_filter[0].strip()
    wcard_filter.Value = str_filter[1].strip()
    return wcard_filter


def check_for_dn(query):
    if args_object.type.strip().lower()=="dn":
        return True
    else:
        return False



####################
# Main Starts Here
####################
if __name__ == "__main__":

    parser = OptionParser()
    parser.add_option("-H", "--Host", dest="ucshost", default=None,
                      help='[Mandatory] Specifies the IP address or the DNS name '
                      'of the UCS server to which user want to connect.')
    parser.add_option("-n", "--port", dest="port", default=None,
                      help="Specify the UCS Manager port.")
    parser.add_option("--NoSsl", action="store_true", dest="no_ssl", default=False,
                      help="If this flag is specified then the connection is made without using SSL protocol.")
    parser.add_option("-u", "--user", dest="user", default=None,
                      help="[Mandatory] Specify UCS Login user name")
    parser.add_option("-p", "--password", dest="password", default=None,
                      help="[Mandatory] Specify UCS user password")
    parser.add_option("--passEnc", dest="pass_enc", default=None,
                      help="Specify UCS user password in Base64 encoding.")
    parser.add_option("-t", "--type", dest="type", default=None,
                      help="[Mandatory] Query type, i.e class or dn. Example -t class or --type dn.")
    parser.add_option("-q", "--query", dest="query", default=None,
                      help='[Mandatory] Value of query class or dn. Example if -t was dn the -q should'
                      'be a dn like sys/chassis-1,sys/chassis-1/blade-1 etc. If -t was class then -q can'
                      'be EquipmentBlade,EquipmentFan etc.')
    parser.add_option("-a", "--attribute", dest="attribute",
                      help='Attribute that user want to fetch value for.'
                      'Either provide just the <attr name> or <attr name>:<user given name>'
                      'which is to displayed in Nagios WebUI.'
                      'Example : For class ProcessorUnit, Speed is one attribute then'
                      'user can provide -a Speed:CPU Speed(Mhz) or -a Speed.')
    parser.add_option("-w", "--warn", dest="w",
                      help="Warning level")
    parser.add_option("-c", "--critical", dest="c",
                      help="Critical level")
    parser.add_option("-r", "--regex", dest="r",
                      help="Regular Expression for matching the pass or fail condition")

    parser.add_option("--proxy",
                      help='''Specifies a Proxy object that contains proxy URL and
                      optionally authentication information.
                      Example: --proxy \"http://<Proxy IP>:<Port> ''')

    parser.add_option("-R","--inHierarchical", action="store_true", dest="hierarchical_flag", default=False,
                      help='If this flag is specified this will provide a '
                      'hierarchical top view status for all the elements under '
                      'the given class or dn.')
    parser.add_option("--debug", action="store_true", dest="debug", default=False,
                      help='If this flag is specified it will print the xml'
                      'communication between the plugin and UCS Host.'
                      'It will also print the error trace in case an '
                      'error had occured.Use this for debug purpose only.')
    parser.add_option("-v", "--verbose", action="store_true",
                      dest="verbose_flag", default=False,
                      help='This flag is used with the inHierarchical flag and '
                      'if provided it will print detailed status information '
                      'for all the elements under the given class or dn.')

    parser.add_option("-f", "--filter", dest="filter", default=None,
                      help='Provide a filter string in the format attribute:value.'
                      'This filter is only valid for query type class.'
                      'User can provide wildcard filter which uses standard '
                      'regular expression syntax.')

    parser.add_option("--getPerfStats", dest="getPerformanceStats", default=False,action="store_true",
                      help='If this flag is specified this will provide a'
                      'preformance data for the Nagios to use to plot graphs.'
                      'This flag can only be used when -a option is set.')

    parser.add_option("-F","--faultDetails", action="store_true",
                      dest="only_faults", default=False,
                      help='If specified it will work with inHierarchical flag '
                      'and will look for faults under the given class or dn.'
                      'It is quick way for checking the over all status '
                      'of the given dn or class')
    parser.add_option("-S","--useSharedSession", action="store_true",
                      dest="reuse_cookie", default=False,
                      help='If specified it will try and share an existing UCSM'
                      'connection for the specified user.'
                      'Else it will create a new user session every time.')
    parser.add_option("--version", action="store_true",
                      dest="version", default=False,
                      help='If specified it will print the current Cisco UCSM Monitoring plugin version.'
                      'NOTE: All the other options will be ignored.')
    (args_object, args) = parser.parse_args()
    # Print Plugin Version
    if args_object.version:
        print "Cisco UCSM Nagios Monitoring Plugin version : ", UCSM_PLUGIN_VERSION
        sys.exit(STATE_UNKNOWN)
    # Check if ucs host is provide as input or not
    if check_for_valid_inputs(args_object.ucshost):
        parser.print_help()
        parser.error('Provide ucs host name')
    # Check if user is provided for the ucs host
    if check_for_valid_inputs(args_object.ucshost):   # if user is not given
        parser.print_help()
        parser.error('Provide user name for the given ucshost')
    # Check if password is provided for the ucs host
    if (check_for_valid_inputs(args_object.password) and
            check_for_valid_inputs(args_object.pass_enc)):
            # if password is not given
            parser.print_help()
            parser.error('Provide ucs password for the given ucshost ')
    # Check if type is provided
    if check_for_valid_inputs(args_object.type):   # if type is not given
        parser.print_help()
        parser.error('Provide query type dn or class.')
    # Check if query dn or class is provided
    if check_for_valid_inputs(args_object.query):   # if type is not given
        parser.print_help()
        parser.error('Provide query dn or class.')

    # Debug - print args
    # use_fault_for_result_flag is used for checking if the UCS faults are to be considered
    # for Nagios status or not.If user has provided an option a and r or w and c then
    # we will discard  UCS fault status for the over all Nagios status.
    use_fault_for_result_flag = True

    if (args_object.r is not None and
            (args_object.w is not None or 
                args_object.c is not None)):
        print 'Provide either regular expression \'r\' or' \
              ' warning \'w\' and critical \'c\' values'
        sys.exit(STATE_UNKNOWN)

    only_attr_flag = False
    if args_object.attribute is not None and args_object.attribute.strip() == "":
        print "Provide Attribute for the selected class or dn"
        sys.exit(STATE_UNKNOWN)
    if args_object.attribute is not None and \
        (args_object.r is None and \
         (args_object.w is None and args_object.c is None)):
            only_attr_flag = True
    elif args_object.attribute is not None and not re.search(",", args_object.attribute) and \
        (args_object.r is None and (args_object.w is None or args_object.c is None)):
        print "Provide both warning and critical values for the attribute"
        sys.exit(STATE_UNKNOWN)
    elif args_object.attribute is not None and re.search(",", args_object.attribute) and \
        (args_object.r is not None or args_object.w is not None or args_object.c is not None): 
         print "For multiple attribute, warning and critical or regex can not be set."
         sys.exit(STATE_UNKNOWN)
    elif args_object.attribute is None and args_object.r is not None:
        print "Provide an attribute for the provided regular expression."
        sys.exit(STATE_UNKNOWN)
    elif args_object.attribute is None and \
            (args_object.w is not None or args_object.c is not None):
            print "Provide an attribute for the provided warning and critical values."
            sys.exit(STATE_UNKNOWN)

    if args_object.hierarchical_flag and \
            (args_object.attribute is not None or args_object.r is not None or
             (args_object.w is not None or args_object.c is not None)):
            print ('Attribute \'a\' , regular expression \'r\' , warning \'w\' and '
                   'critical \'c\' values are not supported with inHierarchical flag.')
            sys.exit(STATE_UNKNOWN)
    elif args_object.verbose_flag and not args_object.hierarchical_flag:
        print "Verbose flag is only valid when inHierarchical flag is defined."
        sys.exit(STATE_UNKNOWN)
    elif args_object.only_faults and not args_object.hierarchical_flag:
        print " faultDetails flag can only be used with inHierarchical flag."
        sys.exit(STATE_UNKNOWN)

    if args_object.getPerformanceStats and args_object.attribute is None:
        print "--getPerfStats flag can only be used with -a/--attribute option."
        sys.exit(STATE_UNKNOWN)

    if args_object.type.lower().strip() == "dn" and args_object.filter:
        print "CLI argument --filter/-f can not be provided with query type DN"
        sys.exit(STATE_UNKNOWN)
    if args_object.filter is not None and len((args_object.filter).split(":")) != 2:
        print "Provide filter is not in correct format. Should follow 'attribute:value'"
        sys.exit(STATE_UNKNOWN)

    if (args_object.r is not None or
        (args_object.w is not None and args_object.c is not None) or
            only_attr_flag):
        use_fault_for_result_flag = False
        if args_object.w is not None and args_object.c is not None:
            try:
                args_object.w = float(args_object.w)
                args_object.c = float(args_object.c)
                if not args_object.c > args_object.w:
                    print ('Error while checking the -w and -c values. '
                           'For values to be compared,check if -c is greater'
                           ' than -w.')
                    sys.exit(STATE_WARNING)
            except ValueError:
                current_return_state = STATE_WARNING
                print('Error while checking the -w and -c values.'
                      'For value to be compared, check if the -w and -c '
                      'are either int or float values only.')
                sys.exit(STATE_WARNING)

    # Clean the query variable
    query = args_object.query.strip("'").strip()
    in_filter_fault = FilterFilter()

    # Check if the type is class and if it is then does it
    # have "/" as character
    if args_object.type.lower().strip() == 'class':
        if check_for_dn(query):
            print "Provide a valid Class name"
            sys.exit(STATE_WARNING)
        else:
            # Using the filter for the class
            if args_object.filter is not None:
                in_filter_fault.AddChild(get_wcard_filter(query,
                                                          args_object.filter))

    elif args_object.type.lower().strip() == 'dn':
        if not check_for_dn(query):
            print "Provide a valid Dn"
            sys.exit(STATE_WARNING)
        else:
            query = query.strip().strip('/')
    else  :
        print "Input parameter Type(-t,--type) can only take either class or dn as input."
        sys.exit(STATE_UNKNOWN)

    # Check if the password is Enc or not
    if args_object.password is None:
        try:
            password = b64decode(args_object.pass_enc)
        except TypeError, err:
            print 'Error while trying to decode password.' \
                'Please check the provided password.'
            print "Error Message : " + str(err)
            sys.exit(STATE_UNKNOWN)
    else:
        password = args_object.password

    # Check if the attribute
    ucs_object = None
    return_value = STATE_UNKNOWN

    try:
        if not args_object.reuse_cookie:
            ucs_object = UcsHandle()
            if args_object.debug:
                ucs_object.SetDumpXml()
            if args_object.port is None:
                if args_object.no_ssl:
                    port = 80
                else:
                    port = 443
            else:
                port = int(args_object.port)
            ucs_object.Login(args_object.ucshost, args_object.user,
                               password, args_object.no_ssl,
                               port, args_object.debug,
                               args_object.proxy)
        else:
            ucs_object = login_ucs(args_object.ucshost, args_object.user,
                                   password, args_object.no_ssl,
                                   args_object.port, args_object.debug,
                                   args_object.proxy)
            if ucs_object == ERR_RETRY:
                        ucs_object = login_ucs(args_object.ucshost, args_object.user,
                                               password, args_object.no_ssl,
                                               args_object.port, args_object.debug,
                                               args_object.proxy)
        mo_list = None

        if ucs_object is not None:
            # # If -a,-r,-w or -c is passed then the result will be based on the
            # the given regexp or w and c values
            if not use_fault_for_result_flag:
                return_state = STATE_OK
                current_return_state = STATE_OK
                attr_text = ""
                preformance_data = ""

                if args_object.type.lower().strip() == 'dn':
                    get_response = ucs_object.ConfigResolveDn(query)
                    if get_response.errorCode != 0:
                        raise UcsException(get_response.errorCode, get_response.errorDescr)
                    if not get_response.OutConfig or \
                            get_response.OutConfig is None:
                        attr_text = "Check if the Dn '%s' exists on the given UCS host." % (query)
                        return_state = STATE_WARNING
                        raise Exception(attr_text)
                    else:
                        mo_list = get_response.OutConfig.GetChild()

                elif args_object.type.lower().strip() == 'class':
                    query = word_to_upper(query)
                    get_response = ucs_object.ConfigResolveClass(classId=query,
                                                                 inFilter=in_filter_fault,
                                                                 inHierarchical=False)
                    if get_response.errorCode != 0:
                        raise UcsException(get_response.errorCode, get_response.errorDescr)
                    if not get_response.OutConfigs or get_response.OutConfigs is None:
                        attr_text = "Check if the Class '%s' exists on the given UCS host." % (query) +END_DELIMITER\
                            + 'In case you have provided a filter then please check if the attribute that you want'+END_DELIMITER\
                            + 'to filter exists. Else there is no data for the provided filter value.'
                        return_state = STATE_WARNING
                        raise Exception(attr_text)
                    else:
                        mo_list = get_response.OutConfigs.GetChild()
                        if not mo_list:
                            attr_text = "Check if any data exists for the provided Class name '%s'. " % (query)
                            return_state = STATE_WARNING
#                             raise Exception(attr_text)
                for mo in mo_list:
                    if only_attr_flag:
                        if re.search(",", args_object.attribute):
                            # multiple attributes are passed
                            attr_list = args_object.attribute.split(',')
                        else:
                            attr_list = [args_object.attribute]

                        attr_text += get_service_status_text(return_state) + mo.Dn + " - "

                        for attr in attr_list:
                            if attr.strip() != "":
                                attr_value = get_attribute_value(attr.strip(), mo)
                                if attr_value[1] is not None:
                                    attr_given_name = attr_value[1]
                                    attr_text += attr_given_name + " : " + \
                                        attr_value[0] + ATTR_DELIMITER
                                    preformance_data += attr_given_name + "=" + str(attr_value[0]) + " "
                                else:
                                    attr_text += attr + " : " + attr_value[0] +\
                                        ATTR_DELIMITER
                                    preformance_data += attr + "=" + str(attr_value[0]) + " "
                        attr_text = attr_text.strip(ATTR_DELIMITER) + END_DELIMITER
                        return_value = return_state
                    else:
                        attr_value = get_attribute_value(args_object.attribute, mo)

                        # For regexp passed
                        if (args_object.r is not None):
                            if re.search(args_object.r, attr_value[0]):
                                current_return_state = STATE_OK
                            else:
                                current_return_state = STATE_CRITICAL
                            args_object.w = ""
                            args_object.c = ""
                        # For W and C values
                        else:
                            try:
                                converted_value = float(attr_value[0])
                            except ValueError:
                                current_return_state = STATE_WARNING
                                raise Exception('Error while trying to comapare'
                                                + ' \'' + str(attr_value[0]) + '\' ' +
                                                'with the given w and c values.')
                            if converted_value < args_object.w:
                                current_return_state = STATE_OK
                            elif (args_object.w <= converted_value) and (args_object.c >= converted_value):
                                current_return_state = STATE_WARNING
                            else:
                                current_return_state = STATE_CRITICAL

                        if attr_value[1] is not None:
                            attr_given_name = attr_value[1]
                            attr_text += get_service_status_text(current_return_state) + \
                                mo.Dn+" - "+attr_given_name + \
                                " : " + attr_value[0]+END_DELIMITER
                            preformance_data += attr_given_name + "=" + str(attr_value[0]) +";" +str(args_object.w)+ ";" + str(args_object.c)+ ";;;" + " "
                        else:
                            attr_text += get_service_status_text(current_return_state) + \
                                mo.Dn+" - "+args_object.attribute +\
                                " : " + attr_value[0]+END_DELIMITER
                            preformance_data += args_object.attribute + "=" + str(attr_value[0]) +";" +str(args_object.w)+ ";" + str(args_object.c)+ ";;;" + " "
                    if current_return_state > return_state:
                        return_state = current_return_state

################# For Loop END ################
                if args_object.type.lower().strip() == 'class':
                    nagios_text = "Overall Status : " + get_service_status_text(return_state) + \
                        END_DELIMITER + attr_text.strip(END_DELIMITER).strip(ATTR_DELIMITER)
                else:
                    nagios_text = (attr_text.strip(END_DELIMITER)).strip(ATTR_DELIMITER)
                if args_object.getPerformanceStats:
                    nagios_text = nagios_text + "|" + preformance_data.strip()
                return_value = return_state

            else:
                # Find the Fault and inventory information  in case
                # only dn or class is passed work with UCS Fault Details
                # dn = query
                nagios_fault_dict = get_fault_details(ucs_object, query, in_filter_fault,
                                                      args_object.hierarchical_flag,
                                                      args_object.verbose_flag, args_object.only_faults)
                nagios_status = STATE_OK
                nagios_fault_text = ""
                nagios_fault_status = ""
                preformance_data = ""
                for key in nagios_fault_dict.iterkeys():
                    nagios_fault_text_with_status = nagios_fault_dict[key]
                    # Check for final status
                    if nagios_status < nagios_fault_text_with_status[0]:
                        nagios_status = nagios_fault_text_with_status[0]
                    if nagios_fault_text_with_status[1] is not None:
                        nagios_fault_text += nagios_fault_text_with_status[1]
                    if (nagios_fault_text_with_status[0] is None) or \
                       (nagios_fault_text_with_status[2] is None):
                        # Debug : print str(nagios_fault_text_with_status)
                        continue
                    try:
                        preformance_data += nagios_fault_text_with_status[2].split("|")[1] + " "
                    except:
                        pass
                    nagios_fault_status += key + ":" + \
                        get_service_status_text(nagios_fault_text_with_status[0]) + \
                        nagios_fault_text_with_status[2].split("|")[0] + END_DELIMITER
                if preformance_data.strip() != "":
                    if nagios_fault_text != "":
                        nagios_fault_text = nagios_fault_text.rstrip(END_DELIMITER) + "|" + preformance_data.strip()
                    else:
                        nagios_fault_status = nagios_fault_status.rstrip(END_DELIMITER) + "|" + preformance_data.strip()
                else :  
                    nagios_fault_text = nagios_fault_text.rstrip(END_DELIMITER)
                # Get Inventory Details only in case of a DN for class skip
                if nagios_fault_status.strip() == "":
                    nagios_text = nagios_fault_text.strip()
                else:
                    nagios_text = nagios_fault_status + "\n" + nagios_fault_text.strip()
                return_value = nagios_status
            print(nagios_text.strip().strip("|"))
            if not args_object.reuse_cookie:
                ucs_object.Logout()
            # Debug : print(nagios_fault_status)
        else:
            # unable to Login to UCS
            err_txt = "Unable to login to UCSM '%s'" %args_object.ucshost + \
                        END_DELIMITER+'Try login from web interface, if that works, ' + \
                        'then check if user has sufficient privileges to \n' + \
                        'work with the temp files under the defined directory %s.' % PLUGIN_CFG_DICT['CISCO_TEMP_PATH']
            raise Exception(err_txt)

    except Exception, err:
        nagios_text = "Error is of Type :  ", err.__class__.__name__, " Message >>", str(err)
        nagios_text = " ".join(nagios_text) + " \nError while trying to run the UCS Nagios monitoring service.\n" + \
        "Check for Nagios logs as it may help finding error details. "
        if os.isatty(sys.stdin.fileno()):
            print nagios_text.strip()
        else:
            print convert_to_html(nagios_text)
        # Debug
        if args_object.debug:
            print "Exception:", str(err)
            import traceback, sys
            print '-' * 60
            traceback.print_exc(file=sys.stdout)
            print '-' * 60
            from UcsSdk import Version
            print '-' * 20, "Additional information", '-' * 20
            print "Python version : ", sys.version
            print "Python UCSM SDK version : " , Version.__version__
            print "Cisco UCSM Nagios Monitoring Plugin version : ", UCSM_PLUGIN_VERSION
        if not args_object.reuse_cookie:
            try:
                ucs_object.Logout()
            except:
                pass
    sys.exit(return_value)
