def _setup_log(folder, no_log): """Demonstrate setup and provide examples on use of the logging methods :param folder: The folder to put log files in. If None, use the local directory :type folder: str, None :param no_log: If True, do not create a log file :type no_log: bool """ global _DEBUG_IP, _DEBUG_ID, _DEBUG_VERBOSE, __version__, _DEBUG_EXCEPTION # Set up the folder to use for logging. if not no_log: brcdapi_log.open_log(folder) # As an example, echo the module variables ml = [ 'Module : cli_poll_to_api', 'Version : ' + __version__, 'User ID : ' + _DEBUG_ID, 'Password : xxxxxx', 'IP address: ' + brcdapi_util.mask_ip_addr(_DEBUG_IP, keep_last=True) ] # Every call to brcdapi_log.log is preceded with a time stamp so this list gets onetime stamp brcdapi_log.log(ml, echo=True) if _DEBUG_VERBOSE: brcdapi_log.log('Verbose debug enabled', True) # This gets it's own time stampe # exception() precedes the message, or list of message, with a stack trace, calls log(), and flushes the file cache. if _DEBUG_EXCEPTION: buf = 'Ignore the preceding stack trace. It is only to illustrate the use of the brcdapi.log.expection() method' brcdapi_log.exception(buf, True)
def get_key_val(obj, keys): """Spins through a list of keys separated by a '/' and returns the value associated with the last key. :param obj: Starting point in the object :type obj: dict, ProjectObj, FabricObj, SwitchObj, PortObj, ZoneCfgObj, ZoneObj, PortObj, LoginObj :param keys: Sting of keys to look through :type keys: str :return: Value associated with last key. None if not found :rtype: int, float, str, list, tuple, dict """ global error_asserted if obj is None: return None # Saves the calling method of having to determine they are working on a valid object if hasattr(obj, 'r_get') and callable(obj.r_get): return obj.r_get(keys) if not isinstance(obj, dict): brcdapi_log.exception('Object type, ' + str(type(obj)) + ', not a dict or brcddb object,', True) error_asserted = True return None key_l = keys.split('/') if len(key_l) == 0: return None last_key = key_l[len(key_l)-1] v = obj for k in key_l: if isinstance(v, dict): v = v.get(k) elif k != last_key: brcdapi_log.exception('Object type, ' + str(type(v)) + ', for ' + k + ', in ' + keys + ' not a dict or brcddb object ', True) error_asserted = True return None return v
def api_request(session, uri, http_method, content): """Interface in front of _api_request to handle retries when services are unavailable :param session: Session object returned from login() :type session: dict :param uri: full URI :type uri: str :param http_method: Method for HTTP connect. :param content: The content, in Python dict, to be converted to JSON and sent to switch. :type content: dict :return: Response and status in pyfos_auth.is_error() and pyfos_auth.formatted_error_msg() friendly format :rtype: dict """ global _MAX_RETRIES if uri is None: # An error occurred in _format_uri() buf = 'Missing URI' brcdapi_log.exception(buf, True) return pyfos_auth.create_error(brcdapi_util.HTTP_BAD_REQUEST, 'Missing URI', buf) obj = _api_request(session, uri, http_method, content) retry_count = _MAX_RETRIES retry_flag, wait_time = _retry(obj) while retry_flag and retry_count > 0: time.sleep(wait_time) obj = _api_request(session, uri, http_method, content) retry_count -= 1 retry_flag, wait_time = _retry(obj) return obj
def fabric_page(wb, tc, sheet_i, sheet_name, sheet_title, fabric_obj): """Creates the fabric summary page :param wb: Workbook object :type wb: class :param tc: Table of context page. A link to this page is place in cell A1 :type tc: str, None :param sheet_i: Relative location for this worksheet :type sheet_i: int :param sheet_name: Sheet (tab) name :type sheet_name: str :param sheet_title: Title for sheet :type sheet_title: str :param fabric_obj: Fabric object :type fabric_obj: FabricObj :rtype: None """ # Validate the user input err_msg = list() if fabric_obj is None: err_msg.append('FabricObj was not defined.') elif brcddb_class_util.get_simple_class_type(fabric_obj) != 'FabricObj': err_msg.append('Wrong object type, ' + str(type(fabric_obj)) + 'Must be brcddb.classes.fabric.FabricObj.') if len(err_msg) > 0: brcdapi_log.exception(err_msg, True) return # Set up the worksheet and add the fabric _setup_worksheet(wb, tc, sheet_i, sheet_name, sheet_title) _fabric_summary(fabric_obj) _maps_dashboard(fabric_obj) _zone_configuration(fabric_obj) return
def _isl_redundant(obj, t_obj): """Check to see if there are at least two ISLs between switch pairs. Ignores connections to AMP :param obj: Switch object from the object list, obj_list, passed to best_practice() :type obj: brcddb.classes.switch.switch_obj :param t_obj: Individual test item from the test_list passed to best_practice(). Not used :type t_obj: dict :return: List of alert dictionaries {'a': alert number, 'p0': p0, 'p1': p1, 'k': '_isl_map'} :rtype: list """ r_list = list() # Validate input obj_type = brcddb_class_util.get_simple_class_type(obj) if obj_type is None: obj_type = str(type(obj)) if obj_type != 'SwitchObj': brcdapi_log.exception('Invalid object type. Expected switch_obj. Received: ' + obj_type, True) return r_list proj_obj = obj.r_project_obj() isl_map = obj.c_trunk_map() for k in isl_map.keys(): switch_pair = isl_map.get(k) if _amp_in_switch_pair(obj, k, switch_pair): continue if len(list(switch_pair.keys())) == 1: r_list.append({'a': t_obj.get('m'), 'p0': brcddb_switch.best_switch_name(obj), 'p1': brcddb_switch.best_switch_name(proj_obj.r_switch_obj(k)), 'k': 'trunk'}) return r_list
def switch_page(wb, tc, sheet_name, sheet_i, sheet_title, s_list, display): """Creates a switch detail worksheet for the Excel report. :param wb: Workbook object :type wb: class :param tc: Table of context page. A link to this page is place in cell A1 :type tc: str, None :param sheet_name: Sheet (tab) name :type sheet_name: str :param sheet_i: Sheet index where page is to be placed. :type sheet_i: int :param sheet_title: Title to be displayed in large font, hdr_1, at the top of the sheet :type sheet_title: str :param s_list: List of switch objects (SwitchObj) to display :type s_list: list, tuple :param display: List of keys to display. Find next instance of switch_key_case. Much less complex than port_page() :type display: dict :rtype: None """ # Validate the user input err_msg = list() if s_list is None: err_msg.append('s_list was not defined.') elif not isinstance(s_list, (list, tuple)): err_msg.append('s_list was type ' + str(type(s_list)) + '. Must be a list or tuple.') if display is None: err_msg.append('display not defined.') if len(err_msg) > 0: brcdapi_log.exception(err_msg, True) return # Set up the worksheed and add each switch _setup_worksheet(wb, tc, sheet_name, sheet_i, sheet_title) for switch_obj in s_list: _add_switch(switch_obj, display)
def checksum(session, fid, echo=False): """Gets a zoning transaction checksum :param session: Session object returned from brcdapi.pyfos_auth.login() :type session: dict :param fid: Logical FID number for the fabric of interest :type fid: int :param echo: If True, echoes any error messages to STD_OUT :type echo: bool :return: checksum :rtype: int, None :return: brcdapi_rest status object :rtype: dict """ # Get the checksum - this is needed to save the configuration. obj = brcdapi_rest.get_request(session, 'brocade-zone/effective-configuration', fid) if _is_error( obj, 'Failed to get zone data from "brocade-zone/effective-configuration"', echo): return None, obj try: return obj.get('effective-configuration').get('checksum'), obj except: brcdapi_log.log('Failed to get checksum', echo) brcdapi_log.exception(pprint.pformat(obj, indent=4), echo) return None, pyfos_auth.create_error( brcdapi_util.HTTP_INT_SERVER_ERROR, brcdapi_util.HTTP_REASON_UNEXPECTED_RESP, 'Missing effective-configuration/checksum')
def get_from_obj(obj, k): """Returns the value associated with a key in / notation for a dict or brcddb.class object :param obj: Dictionary the key is for :type obj: dict :param k: The key :type k: str :return: Value associated with the key. None is returned if the key was not found :rtype: int, str, list, dict, None """ global error_asserted if isinstance(obj, dict): v0 = get_struct_from_obj(obj, k) if v0 is None: return None kl = k.split('/') while len(kl) > 0: k0 = kl.pop(0) v0 = v0.get(k0) if v0 is None: return None # The key was not found if we get here return v0 elif brcddb_class_util.get_simple_class_type(obj) is None: brcdapi_log.exception('Invalid object type.', True) error_asserted = True else: return obj.r_get(k)
def _update_brcddb_obj(objx, obj, uri): global _GEN_CASE_ERROR_MSG if objx is None: return # This happens when fabric information is polled from a switch but the principal fabric switch wasn't # polled and we don't know what the principal fabric switch WWN is. try: tl = uri.split('/') d = objx.r_get(tl[0]) if d is None: d = dict() objx.s_new_key(tl[0], d) for k in obj: v1 = obj.get(k) if k in _ip_list: d.update({k: _convert_ip_addr(v1)}) else: d.update({k: v1}) except: brcdapi_log.exception(_GEN_CASE_ERROR_MSG, True) objx.r_project_obj().s_add_alert(al.AlertTable.alertTbl, al.ALERT_NUM.PROJ_PROGRAM_ERROR, None, _GEN_CASE_ERROR_MSG, '') try: objx.r_project_obj().s_warn_flag() except: try: objx.s_warn_flag() except: pass
def _port_category(switch_obj, dash_obj): p0 = dash_obj.get('name') o_list = brcddb_util.get_key_val(dash_obj, 'objects/object') buf = o_list[0] if '-Port' in buf or 'SFP' in buf: port = buf.split(' ')[1].split(':')[0] port = '0/' + port if '/' not in port else port elif 'Pid' in buf: # I've stumbled across so many quirks in the MAPS dashboard, it wouldn't surprise me in a rule for a removed # port is still in the dashboard. try: port = switch_obj.r_port_obj_for_pid( buf.split(' ')[1].split(':')[0]).r_obj_key() except: return else: brcdapi_log.exception('Unknown MAPS object: ' + buf, True) return sev = dash_obj.get('event-severity') if dash_obj.get( 'event-severity') in _event_severity else 'default' al_num = _event_severity[sev] port_obj = switch_obj.r_port_obj(port) if port_obj is not None and not brcddb_util.has_alert( port_obj, al_num, None, p0, None): port_obj.s_add_alert(al.AlertTable.alertTbl, al_num, None, p0, None)
def pseudo_main(): """Basically the main(). Did it this way so it can easily be used as a standalone module or called from another. :return: Exit code. See exist codes in brcddb.brcddb_common :rtype: int """ ip, user_id, pw, outf, sec, s_flag, vd, c_file, fid, log, nl = parse_args() if vd: brcdapi_rest.verbose_debug = True if s_flag: brcdapi_log.set_suppress_all() if not nl: brcdapi_log.open_log(log) if sec is None: sec = 'none' fid_l = None if fid is None else fid.split(',') ml = ['WARNING!!! Debug is enabled'] if _DEBUG else list() ml.append('IP: ' + brcdapi_util.mask_ip_addr(ip, True)) ml.append('ID: ' + user_id) ml.append('security: ' + sec) ml.append('Output file: ' + outf) ml.append('KPI file: ' + str(c_file)) ml.append('FID List: ' + str(fid)) brcdapi_log.log(ml, True) outf = brcdapi_file.full_file_name(outf, '.json') # Create project proj_obj = brcddb_project.new( "Captured_data", datetime.datetime.now().strftime('%d %b %Y %H:%M:%S')) proj_obj.s_python_version(sys.version) proj_obj.s_description("This is a test") # Login session = api_int.login(user_id, pw, ip, sec, proj_obj) if brcdapi_auth.is_error(session): return brcddb_common.EXIT_STATUS_API_ERROR # Collect the data try: api_int.get_batch(session, proj_obj, _kpi_list(session, c_file), fid_l) except BaseException as e: brcdapi_log.exception( 'Programming error encountered. Exception is: ' + str(e), True) # Logout obj = brcdapi_rest.logout(session) if brcdapi_auth.is_error(obj): brcdapi_log.log(brcdapi_auth.formatted_error_msg(obj), True) # Dump the database to a file if _WRITE: brcdapi_log.log('Saving project to: ' + outf, True) plain_copy = dict() brcddb_copy.brcddb_to_plain_copy(proj_obj, plain_copy) brcdapi_file.write_dump(plain_copy, outf) brcdapi_log.log('Save complete', True) return proj_obj.r_exit_code()
def _compare(r_obj, ref, b_obj, c_obj, control_tbl): """Compares two dict, list, tuple, or brcddb.classes objects :param r_obj: Return object - Dictionary or list of changes :type r_obj: dict, list :param ref: Reference key. :type ref: str :param b_obj: Base object to compare against. :type b_obj: dict, list, tuple, brcddb.classes.* :param c_obj: Compare object :type c_obj: dict, list, tuple, brcddb.classes.* :param control_tbl: Control table. :type control_tbl: dict :return: Number of mismatches found :rtype: int """ global _obj_type_action, _REMOVED, _NEW, _MISMATCH, _INVALID_REF # Make sure we have a valid reference. if not isinstance(ref, str): brcdapi_log.exception('Invalid reference type: ' + str(type(ref)), True) _update_r_obj(r_obj, {'b': '', 'c': '', 'r': _INVALID_REF}) return 0 # Does the base object exist? if b_obj is None: _update_r_obj(r_obj, {'b': ref, 'c': '', 'r': _NEW}) return 1 # Does the compare object exist? if c_obj is None: _update_r_obj(r_obj, {'b': ref, 'c': '', 'r': _REMOVED}) return 1 # Are we comparing the same types? A mix of int and float is OK so that gets normalized to type 'num' b_type = class_util.get_simple_class_type(b_obj) if b_type is None: b_type = 'num' if isinstance(b_obj, (int, float)) else \ str(type(b_obj)).replace('<class ', '').replace('>', '').replace("\'", '') c_type = class_util.get_simple_class_type(c_obj) if c_type is None: c_type = 'num' if isinstance(c_obj, (int, float)) else \ str(type(c_obj)).replace('<class ', '').replace('>', '').replace("\'", '') if b_type != c_type: _update_r_obj(r_obj, {'b': b_type, 'c': c_type, 'r': _MISMATCH}) return 1 if b_type in _obj_type_action: return _obj_type_action[b_type](r_obj, ref, b_obj, c_obj, control_tbl) brcdapi_log.log('Unknown base object type: ' + b_type, True) _update_r_obj(r_obj, {'b': b_type, 'c': '', 'r': _INVALID_REF}) return 1
def p_login_addr_case(port_obj, k, wwn): if wwn is None: return '' try: return port_obj.r_fabric_obj().r_login_obj(wwn).r_get( 'brocade-name-server/port-id') except: brcdapi_log.exception( 'No login address for ' + wwn + '. Switch ' + port_obj.r_switch_obj().r_obj_key() + ', port ' + port_obj.r_obj_key(), True) return 'Unknown'
def align_type(x): """Returns the alignment defintion tuple for the openpyxl libraries :param x: Alignment type listed in font_tbl :type x: str :return: Alignment defintions for openpyxl library :rtype: tuple """ if x in align_tbl: return align_tbl[x] else: brcdapi_log.exception('Unknown align type: ' + x, True) return wrap_alignment
def border_type(x): """Returns the border defintion tuple for the openpyxl libraries :param x: Border type listed in font_tbl :type x: str :return: Border defintions for openpyxl library :rtype: tuple """ if x in border_tbl: return border_tbl[x] else: brcdapi_log.exception('Unknown border type: ' + x, True) return thin_border
def fill_type(x): """Returns the font defintion tuple for the openpyxl libraries :param x: Fill type listed in font_tbl :type x: str :return: Fill defintions for openpyxl library :rtype: tuple """ if x in fill_tbl: return fill_tbl[x] else: brcdapi_log.exception('Unknown fill type: ' + x, True) return lightblue_fill
def _parse_chpid(chpid): """Parses a CHPID macro :param chpid: CHPID PATH macro :type chpid: str :return tag: CHPID and CSS formatted as tag :rtype tag: str :return partition: List of partitions sharing this CHPID :rtype partition: list :return pchid: PCHID :rtype pchid: str :return switch: Switch ID :rtype switch: str """ tag = '' partition = list() pchid = '' switch = '' # Sample CHPID macro: CHPID PATH=(CSS(0),50),SHARED,PARTITION=((SYJ3,SYJ4),(=)),SWITCH=F4,PCHID=168,TYPE=FC # Note that 'CHPID PATH=' is already stripped off so we just have: (CSS(0),4D),SHARED,PARTITION... try: # Tack on 'xxx=xxx' so I don't have handle any elements at the end as a special case. # Get the SWITCH, PARTITION and PCHID x = 0 temp_l = (chpid + ',xxx=xxx').split('=') for buf in temp_l: if x + 1 >= len(temp_l): break next_buf = temp_l[x + 1] if 'PATH' in buf: l, dummy_buf = css_chpid_to_tag(next_buf) tag = l[0] if 'PARTITION' in buf: i = 0 # I've seen anywhwere from 0 to 2 '(' so just skip through them all for chr in next_buf: if chr != '(': break i += 1 partition = next_buf[i:next_buf.find(')')].split(',') elif 'PCHID' in buf: pchid = next_buf.split(',')[0] elif 'SWITCH' in buf: switch = next_buf.split(',')[0] x += 1 except: brcdapi_log.exception('Unknown CHPID macro format:\n' + chpid, True) return tag, partition, pchid, switch
def login(user_id, pw, ip_addr, https='none', proj_obj=None): """Log in and capture a list of supported modules. :param user_id: User ID :type user_id: str :param pw: Password :type pw: str :param ip_addr: IP address :type ip_addr: str :param https: If 'CA' or 'self', uses https to login. Otherwise, http. :type https: None, str :param proj_obj: Project object :type proj_obj: brcddb.classes.project.ProjectObj, None :return: session :rtype: dict """ # Attempt to log in tip = brcdapi_util.mask_ip_addr(ip_addr, True) session = brcdapi_rest.login(user_id, pw, ip_addr, https) if pyfos_auth.is_error(session): brcdapi_log.log(tip + ' Login failed', True) _process_errors(session, '/rest/login', session, proj_obj) return session else: brcdapi_log.log(tip + ' Login succeeded', True) # Figure out what modules this FOS version supports # Step 1: Read all the module information from FOS uri = 'brocade-module-version' obj = brcdapi_rest.get_request(session, uri) if pyfos_auth.is_error(obj): brcdapi_log.log(tip + ' ERROR: ' + uri + '\n' + pyfos_auth.formatted_error_msg(obj), True) return session # Step 2: Parse the module information and add it to the session object kpi_list = list() for mod_obj in obj.get(uri).get('module'): name = mod_obj.get('name') if name is None: brcdapi_log.exception("'name' mising in brocade-module-version", True) continue kpi_list.append(name) try: # I think 'object' will always be there, just empty when there are no objects. Try/Except just in case. for mod_object in mod_obj.get('objects').get('object'): kpi_list.append(name + '/' + mod_object) except: pass session.update(dict(supported_uris=kpi_list)) return session
def pseudo_main(): """Basically the main(). Did it this way so it can easily be modified to be called from another script. :return: Exit code. See exit codes in brcddb.brcddb_common :rtype: int """ # Get the command line input ip_addr, user_id, pw, sec = _get_input() # Login brcdapi_log.log('Attempting login', True) session = brcdapi_rest.login(user_id, pw, ip_addr, sec) if fos_auth.is_error(session): brcdapi_log.log('Login failed. Error message is:', True) brcdapi_log.log(fos_auth.formatted_error_msg(session), True) return -1 brcdapi_log.log([ 'Login succeeded', 'Getting certificates. This will take about 30 sec.' ], True) try: # This try is to ensure the logout code gets executed regardless of what happened. # Get the certificates from the API cert_obj = brcdapi_rest.get_request( session, 'running/brocade-security/security-certificate') except BaseException as e: brcdapi_log.exception( 'Unexpected error encountered. Exception is: ' + str(e), True) # Logout brcdapi_log.log('Attempting logout', True) obj = brcdapi_rest.logout(session) if fos_auth.is_error(obj): brcdapi_log.log('Logout failed. Error message is:', True) brcdapi_log.log(fos_auth.formatted_error_msg(obj), True) return -1 brcdapi_log.log('Logout succeeded.', True) # Display the certificates if fos_auth.is_error(cert_obj): brcdapi_log.exception( 'Failed to capture certificates.' + fos_auth.formatted_error_msg(cert_obj), True) return -1 _cert_detail_report(cert_obj) _cert_summary_report(cert_obj) return 0
def _is_error(obj, msg, echo): """Updates the log file if there was an error :param obj: Object returned from API :type obj: dict :param msg: Message to add to the log buffer :type msg: str :param echo: True - echo message to STD_OUT :type echo: bool :return: Version :rtype: str """ if pyfos_auth.is_error(obj): brcdapi_log.log(msg, echo) brcdapi_log.exception(pyfos_auth.formatted_error_msg(obj), echo) return True return False
def class_getvalue(obj, keys, flag=False): """Returns the value associated with a key. :param obj: Any brcddb.classes object :type obj: ChassisObj, FabricObj, LoginObj, FdmiNodeObj, FdmiPortObj, PortObj, ProjectObj, SwitchObj, ZoneCfgObj \ ZoneObj, AliasObj :param keys: Key who's value is sought. None is allowed to simplify processing lists of keys that may not be present :type keys: str, None :param flag: If True, combine the first two keys into a single key. Used for port keys. :type flag: bool :return: Value associated with key :rtype: any """ if keys is None or obj is None or len(keys) == 0: return None kl = keys.split('/') if flag: # The next key is going to be for the port which is in slot/port notation. The split above will seperate the # 2 keys so the code below puts the port key back together. if len(kl) > 1: kl[0] = kl.pop(0) + '/' + kl[0] else: return None # Someone called this with missing keys if we get here. if hasattr(obj, '_reserved_keys') and kl[0] in obj._reserved_keys: # Typically get here when someone did an obj.r_get() on a reserved key new_obj = _class_reserved(obj, kl.pop(0), ) if len(kl) > 0: s_type = get_simple_class_type(obj) return class_getvalue(new_obj, '/'.join(kl), True if s_type is not None and s_type == 'PortObj' else False) else: return new_obj elif hasattr(obj, '__dict__'): # This is where you go for anything added to a brcddb object v0 = obj while len(kl) > 0: k0 = kl.pop(0) try: v0 = v0.get(k0) if isinstance(v0, dict) else v0.__dict__.get(k0) except: return None # The key was not found if we get here return v0 else: brcdapi_log.exception('Unknown object type: ' + str(type(obj)) + '. keys: ' + keys, True)
def obj_extract(from_obj, to_type): """Extracts a list of objects from an object :param from_obj: The brcddb object the to_obj is to be extracted from :type from_obj: brcddb.classes.* :param to_type: The object simple object type, brcddb.classes.util.get_simple_class_type(), to extract from from_obj :type to_type: str :return: List of objects extracted from from_obj associated with to_obj. Redundant objects removed :rtype: brcddb.classes.* (whatever type to_obj is) """ from_type = brcddb_class_util.get_simple_class_type(from_obj) if from_type is None: brcdapi_log.exception('Unknown from_obj object type: ' + str(type(from_type))) return list() return brcddb_util.remove_duplicates([ obj for obj in _obj_convert_tbl[from_type][to_type](from_obj) if obj is not None ])
def chassis_type(chassis_obj, type_num=False, in_oem='brcd'): """Returns the chassis type (ie: G720) :param chassis_obj: Chassis Object :type chassis_obj: brcddb_classes.chassis.ChassisObj :param type_num: If True, append (type number) to the chassis name :type type_num: bool :param in_oem: 'brcd', 'ibm', 'hpe', 'dell', 'hv', 'netapp', or 'pure' :type in_oem: str :return: Chassis type :rtype: str """ switch_type = _chassis_type(chassis_obj) d = chassis_type_d[switch_type] if in_oem.lower() in d: oem = in_oem.lower() else: brcdapi_log.exception('Invalid oem, ' + str(in_oem), True) oem = 'brcd' return d[oem] + ' (' + str(switch_type) + ')' if type_num else d[oem]
def test_threshold(obj_list, key, test, val): """Filters a list of objects based on a number (int or float) and test condition :param obj_list: list of brcddb classes - see brcddb.class :type obj_list: list :param key: Key for the value to be compared. To look in a substr, seperate keys with a '/'. All keys must be a \ key to a dict or brcddb object :type key: str, list, tuple :param test: Test condition: '>', '<', '==', '=', '>=', '<=', '!=', '!', 'not' :param val: Value to test counter against :type val: int :return: List of objects from obj_list that meet the filter criteria in the same order as obj_list :rtype: list """ return_list = list() # Validate the inputs msg = list() if not isinstance(obj_list, (list, tuple)): msg.append('\nobj_list is type ' + str(type(obj_list)) + '. It must be a list or typle of brcddb objects') if not isinstance(key, str): msg.append('\nkey is type ' + str(type(key)) + '. It must be a type str') if isinstance(test, str): if test not in numerical_test_case: msg.append('\nUnkown "test": ' + test) else: msg.append('\n"test" must be str. Actual type is ' + str(type(test))) if not isinstance(val, (int, float, str)): msg.append('\nval is type ' + str(type(val)) + '. It must be an int, float, or reference (str)') if len(msg) > 0: brcdapi_log.exception('\nInvalid parameter passed to test_threshold\n' + '\n'.join(msg) + '\n', True) return None # Now do the test for obj in obj_list: v = brcddb_util.get_key_val(obj, key) c_val = val if isinstance(val, (int, float)) else brcddb_util.get_key_val(obj, val) if isinstance(v, (int, float)) and isinstance(c_val, (int, float)) and numerical_test_case[test](v, c_val): return_list.append(obj) return return_list
def add_to_obj(obj, k, v): """Adds a key value pair to obj using '/' notation in the key. If the key already exists, it is overwritten. :param obj: Dictionary or brcddb.class object the key value pair is to be added to :type obj: dict :param k: The key :type k: str :param v: Value associated with the key. :type v: int, str, list, dict """ global error_asserted if not isinstance(k, str): brcdapi_log.exception('Invalid key. Expected type str, received type ' + str(type(k)), True) error_asserted = True return key_list = k.split('/') if isinstance(obj, dict): if len(key_list) == 1: obj.update({k: v}) return key = key_list.pop(0) d = obj.get(key) if d is None: d = dict() obj.update({key: d}) add_to_obj(d, '/'.join(key_list), v) elif brcddb_class_util.get_simple_class_type(obj) is None: brcdapi_log.exception('Invalid object type: ' + str(type(obj)) + '. k = ' + k + ', v type: ' + str(type(v)), True) error_asserted = True else: key = key_list.pop(0) if len(key_list) == 0: obj.s_new_key(key, v, True) return r_obj = obj.r_get(key) if r_obj is None: r_obj = dict() obj.s_new_key(key, r_obj) add_to_obj(r_obj, '/'.join(key_list), v)
def _check_sfps(obj_list, t_obj): """Checks SFP levels and adds appropriate alerts to port objects :param obj_list: Port object :type obj_list: list :param t_obj: Individual test item from the test_list passed to best_practice(). Not used :type t_obj: dict """ global _rule_template, sfp_rules, _alert_tbl if sfp_rules is None or obj_list is None: return # Perform all the checks for the SFPs on the switch. enabled_ports = brcddb_search.match_test(obj_list, bp_tables.is_enabled) # SFP data is not valid for disabled ports for rule in sfp_rules: group = 'Unkonwn' if rule.get('Group') is None else rule.get('Group') try: pn_l = rule.get('Mfg. P/N') if pn_l is not None and pn_l != '': for pn in [p.strip() for p in pn_l.split(',')]: plist = brcddb_search.match_test(enabled_ports, {'k': 'media-rdp/part-number', 't': 'exact', 'v': pn}) if len(plist) > 0: online_plist = brcddb_search.match_test(plist, bp_tables.is_online) for k0, obj_0 in _rule_template.items(): for k1, obj_1 in obj_0.items(): val = float(rule.get(k1)) # The threshold to test against m = obj_1.get('a') # Alert number tlist = online_plist if obj_1.get('l') else plist for p_obj in brcddb_search.match_test(tlist, {'k': k0, 't': obj_1.get('t'), 'v': val}): p_obj.s_add_alert(_alert_tbl, m, k0, p_obj.r_get(k0), val) else: brcdapi_log.log('Missing P/N in ' + sfp_rules + ', Group: ' + str(group), True) except: brcdapi_log.exception('Invalid SFP rules file ' + sfp_rules + '. Group: ' + str(group), True) return return
def _check_best_practice(obj_list, test_list): """Checks for defined conditions and adds an alert for every out of bounds condition. :param obj_list: A list of dictionaries or brcdapi objects to search. Must all be the same type :type obj_list: dict, list, tuple :param test_list: Pointer to table of best practice rules. See brcddb.app_data.bp_tables for details :type test_list: dict """ global _alert_tbl # Validate user input if len(obj_list) == 0: return if not isinstance(test_list, (list, tuple)): brcdapi_log.exception('Invalid test_list type, ' + str(type(test_list)), True) return # Spin through each item in the test_list and perform the specified test for t_obj in test_list: if 'skip' in t_obj and t_obj.get('skip'): continue special = t_obj.get('s') if special is not None: if special in _bp_special_case_tbl: _bp_special(obj_list, t_obj) elif special in _bp_special_list_case_tbl: _bp_special_list(obj_list, t_obj) else: brcdapi_log.exception( 'Unknown special test case: ' + str(special) + ', type: ' + str(type(special)), True) else: for obj in brcddb_search.match_test(obj_list, t_obj.get('l'), t_obj.get('logic')): # See documentation in brcddb.app_data.bp_tables for an explanation of 'm', 'p0', 'p0h', 'p1', & 'p1h' p0 = t_obj.get('p0h') if t_obj.get('p0h') is not None else obj.r_get(t_obj.get('p0')) p1 = t_obj.get('p1h') if t_obj.get('p1h') is not None else obj.r_get(t_obj.get('p1')) obj.s_add_alert(_alert_tbl, t_obj.get('m'), brcddb_util.convert_to_list(t_obj.get('l'))[0].get('k'), p0, p1)
def _isl_bw(obj, t_obj): """Check to see that all trunk masters logged in at the same speed :param obj: Switch object from the object list, obj_list, passed to best_practice() :type obj: brcddb.classes.switch.switch_obj :param t_obj: Individual test item from the test_list passed to best_practice(). Not used :type t_obj: dict :return: List of alert dictionaries {'a': alert number, 'p0': p0, 'p1': p1, 'k': '_isl_map'} :rtype: list """ r_list = list() # Validate input obj_type = brcddb_class_util.get_simple_class_type(obj) if obj_type is None: obj_type = str(type(obj)) if obj_type != 'SwitchObj': brcdapi_log.exception('Invalid object type. Expected switch_obj. Received: ' + obj_type, True) return r_list proj_obj = obj.r_project_obj() isl_map = obj.c_trunk_map() for k in isl_map.keys(): switch_pair = isl_map.get(k) if _amp_in_switch_pair(obj, k, switch_pair): continue speeds = list() for k1 in switch_pair.keys(): try: s = switch_pair.get(k1)[0][0].r_get('fibrechannel/speed') if s is not None: speeds.append(s) except: pass # We get here if all switches in the project were not polled if len(brcddb_util.remove_duplicates(speeds)) > 1: r_list.append({'a': t_obj.get('m'), 'p0': brcddb_switch.best_switch_name(obj), 'p1': brcddb_switch.best_switch_name(proj_obj.r_switch_obj(k)), 'k': 'trunk'}) return r_list
def _update_brcddb_obj_from_list(objx, obj, uri, skip_list=None): """Adds a FOS API request response that is a list. Each item in the list is added to a brcddb class object All parameters as in comments above except: :param skip_list: Skip list. List of elements to not add to objx :type skip_list: None, list, tuple """ global _GEN_CASE_ERROR_MSG sl = list() if skip_list is None else skip_list try: tl = uri.split('/') d = objx.r_get(tl[0]) if d is None: d = dict() objx.s_new_key(tl[0], d) d1 = d.get(tl[1]) if d1 is None: d1 = dict() d.update({tl[1]: d1}) for k in obj: if k not in sl: v1 = obj.get(k) if k in _ip_list: d1.update({k: _convert_ip_addr(v1)}) else: d1.update({k: v1}) except: brcdapi_log.exception(_GEN_CASE_ERROR_MSG, True) objx.r_project_obj().s_add_alert(al.AlertTable.alertTbl, al.ALERT_NUM.PROJ_PROGRAM_ERROR, None, _GEN_CASE_ERROR_MSG, '') try: objx.r_project_obj().s_warn_flag() except: try: objx.s_warn_flag() except: pass
def paren_content(buf, p_remove=False): """Returns the contents of a string within matching parenthesis. First character must be '(' :param buf: String to find text within matching parenthesis :type buf: str :param p_remove: If True, remove the leading and trailing parenthesis :return p_text: Text within matching parenthesis :rtype p_text: str :return x_buf: Remaind of buf after matching parenthesis have been found :rtype x_buf: str """ global error_asserted p_count = 0 r_buf = list() buf_len = len(buf) if len(buf) > 1 and buf[0] == '(': p_count += 1 # The first character must be ( r_buf.append('(') for c in buf[1:]: r_buf.append(c) if c == '(': p_count += 1 elif c == ')': p_count -= 1 if p_count == 0: break if p_count != 0: brcdapi_log.exception('Input string does not have matching parenthesis:\n' + buf, True) error_asserted = True r_buf = list() remainder = '' if len(buf) - len(r_buf) < 1 else buf[len(r_buf):] if len(r_buf) > 2 and p_remove: r_buf.pop() r_buf.pop(0) return ''.join(r_buf), remainder