def _merge_zones(change_d, base_fab_obj, add_fab_obj): """Merges the zones from two fabrics :param change_d: Dictionary of alias changes as returned from brcddb.util.compare.compare() :type change_d: dict :param base_fab_obj: brcddb fabric object for the fabric we are adding the zones from add_fab_obj to :type base_fab_obj: brcddb.classes.fabric.FabricObj :param add_fab_obj: brcddb fabric object with the zones to be added to base_fab_obj :type add_fab_obj: brcddb.classes.fabric.FabricObj :return: Error message list. If empty, no errors encountered :rtype: list """ # Basic prep rl = list() if change_d is None: return rl base_fab_name = brcddb_fabric.best_fab_name(base_fab_obj, True) add_fab_name = brcddb_fabric.best_fab_name(add_fab_obj, True) # Add what needs to be added or report differences for zone, change_obj in change_d.items(): change_type = change_obj.get('r') if change_type is None or change_type == 'Changed': # This is a simple pass/fail. No need to look further rl.append('Zone ' + zone + ' in ' + base_fab_name + ' does not match the same zone in ' + add_fab_name) elif change_type == 'Added': add_obj = add_fab_obj.r_zone_obj(zone) base_fab_obj.s_add_zone(zone, add_obj.r_type(), add_obj.r_members(), add_obj.r_pmembers()) return rl
def _project_page(wb, sheet_index, b_proj_obj, c_proj_obj, c_obj): """Recursively iterates through a list of changes from compare.compare() for fabric. Create fabric pages as needed :param wb: Workbook object :type wb: dict :param sheet_index: Starting sheet index :type sheet_index: int :param b_proj_obj: Project object for base (project we are comparing against). Typically the older project. :type b_proj_obj: brcddb.classes.project.ProjectObj :param c_proj_obj: Comparison project object. Typically the newer project. :type c_proj_obj: brcddb.classes.project.ProjectObj :param c_obj: This is the object from compare.compare() that we are working on :type c_obj: dict :return sheet_index: Next sheet index :rtype sheet_index: int :return tbl_contents: Table of contents for the fabrics :rtype. tbl_contents: list """ # Set up the table of contents and sheet headers content = [ dict(font='hdr_1', align='wrap', disp='Project changes'), dict(), dict(font='hdr_2', align='wrap', disp='Fabrics Added:'), ] # Add fabric changes for obj in [d for d in c_obj['_fabric_objs'].values() if d['r'] == 'Added']: content.append(dict(font='std', align='wrap', disp=brcddb_fabric.best_fab_name(c_proj_obj.r_fabric_obj(obj.get('c')), True))) content.extend([dict(), dict(font='hdr_2', align='wrap', disp='Fabrics Removed:')]) for obj in [d for d in c_obj['_fabric_objs'].values() if d['r'] == 'Removed']: content.append(dict(font='std', align='wrap', disp=brcddb_fabric.best_fab_name(b_proj_obj.r_fabric_obj(obj.get('b')), True))) # Add switch changes content.extend([dict(), dict(font='hdr_2', align='wrap', disp='Switches Added:')]) for obj in [d for d in c_obj['_switch_objs'].values() if d['r'] == 'Added']: content.append(dict(font='std', align='wrap', disp=brcddb_switch.best_switch_name(c_proj_obj.r_switch_obj(obj.get('c')), True))) content.extend([dict(), dict(font='hdr_2', align='wrap', disp='Switches Removed:')]) for obj in [d for d in c_obj['_switch_objs'].values() if d['r'] == 'Removed']: content.append(dict(font='std', align='wrap', disp=brcddb_switch.best_switch_name(b_proj_obj.r_switch_obj(obj.get('b')), True))) # Add chassis changes content.extend([dict(), dict(font='hdr_2', align='wrap', disp='Chassis Added:')]) for obj in [d for d in c_obj['_chassis_objs'].values() if d['r'] == 'Added']: content.append(dict(font='std', align='wrap', disp=brcddb_chassis.best_chassis_name(c_proj_obj.r_chassis_obj(obj.get('c')), True))) content.extend([dict(), dict(font='hdr_2', align='wrap', disp='Chassis Removed:')]) for obj in [d for d in c_obj['_chassis_objs'].values() if d['r'] == 'Removed']: content.append(dict(font='std', align='wrap', disp=brcddb_chassis.best_chassis_name(b_proj_obj.r_chassis_obj(obj.get('b')), True))) # Sheet name and title sname = 'Project_Changes_' + str(sheet_index) report_utils.title_page(wb, None, sname, sheet_index, 'Project Changes', content, 80) return sheet_index+1, [dict(s=sname, d='Project Changes')]
def _fabric_add_to_content(obj, b_obj, c_obj, content): """Same as _basic_add_to_content() but assumes the data are WWNs and converts them to fabric names""" start = len(content) if obj is not None: proj_obj = obj.r_project_obj() for k, v in obj.items(): b_buf = brcddb_fabric.best_fab_name(proj_obj.r_fabric_obj(v.get('b')), True) c_buf = brcddb_fabric.best_fab_name(proj_obj.r_fabric_obj(v.get('c')), True) _content_append(dict(font='std', align='wrap', disp=('', b_buf, c_buf, v.get('r'))), content) if len(content) == start: content.append(dict(merge=4, font='std', align='wrap', disp=('No changes',)))
def _fabric_ts(o, k): """Returns the title of the sheet, which is also used in the report summary page, and the sheet name :param o: brcddb class object from which the key, k, is to be retrieved. So far, this has only been a project object :type o: brcddb.classes.project.ProjectObj :param k: The key for the object to retrieve from o :type k: key, str :return title: Sheet title :rtype title: str :return name: Sheet name :rtype name: str """ obj = o.r_fabric_obj(k) return brcddb_fabric.best_fab_name(obj, True), brcddb_fabric.best_fab_name(obj, False)
def _scan_fabrics(proj_obj): """Scan the project for each fabric and list the fabric WWN, FID , and zone configurations :param proj_obj: Project object :type proj_obj: brcddb.classes.project.ProjectObj :return: Status code :rtype: int """ ec = brcddb_common.EXIT_STATUS_OK # Prepare the fabric display ml = ['', 'Fabric Scan (* indicates the effective zone config)', ''] for fab_obj in proj_obj.r_fabric_objects(): eff_zonecfg = fab_obj.r_defined_eff_zonecfg_key() ml.append(brcddb_fabric.best_fab_name(fab_obj, wwn=True)) ml.append( ' FID: ' + ', '.join([str(fid) for fid in brcddb_fabric.fab_fids(fab_obj)])) for buf in fab_obj.r_zonecfg_keys(): if isinstance(eff_zonecfg, str) and eff_zonecfg == buf: ml.append(' Zone Config: ' + '*' + buf) elif buf != '_effective_zone_cfg': ml.append(' Zone Config: ' + buf) ml.append('') # Wrap up and print fabric information if len(ml) == 0: ml.append('No fabrics specified.') ec = brcddb_common.EXIT_STATUS_INPUT_ERROR brcdapi_log.log(ml, True) return ec
def _scan_fabrics(proj_obj): """Scan the project for each fabric and list the fabric WWN, FID , and zone configurations :param proj_obj: Project object :type proj_obj: brcddb.classes.project.ProjectObj :return: List of fabric detail messages :rtype: list """ # Prepare the fabric display ml = ['', 'Fabric Scan (* indicates the effective zone config)', ''] for fab_obj in proj_obj.r_fabric_objects(): eff_zonecfg = fab_obj.r_defined_eff_zonecfg_key() ml.append('From: ' + fab_obj.r_get('zone_merge/file')) ml.append(brcddb_fabric.best_fab_name(fab_obj, wwn=True)) ml.append( ' FID: ' + ', '.join([str(fid) for fid in brcddb_fabric.fab_fids(fab_obj)])) for buf in fab_obj.r_zonecfg_keys(): if isinstance(eff_zonecfg, str) and eff_zonecfg == buf: ml.append(' Zone Config: ' + '*' + buf) elif buf != '_effective_zone_cfg': ml.append(' Zone Config: ' + buf) ml.append('') return ml
def dup_wwn(proj_obj): """Searches all fabrics in the project for duplicate WWNs. :param proj_obj: Project object :type proj_obj: ProjectObj :return: List of login objects for the duplicate WWNS. None entry seperates multiple duplicates :rtype: list """ dup_login = list() if not _DUP_WWN_CHECK: return dup_login dup_wwn = list() for fabObj in proj_obj.r_fabric_objects(): other_fab_list = proj_obj.r_fabric_objects() other_fab_list.remove(fabObj) for wwn in fabObj.r_login_keys(): dup_login_len = len(dup_login) for fobj in other_fab_list: if fobj.r_login_obj(wwn) is not None: if wwn not in dup_wwn: dup_wwn.append(wwn) proj_obj.s_add_alert(al.AlertTable.alertTbl, al.ALERT_NUM.PROJ_DUP_LOGIN, None, wwn) login_obj = fobj.r_login_obj(wwn) if login_obj not in dup_login: dup_login.append(login_obj) login_obj.s_add_alert( al.AlertTable.alertTbl, al.ALERT_NUM.LOGIN_DUP_LOGIN, None, brcddb_fabric.best_fab_name(fabObj)) login_obj = fabObj.r_login_obj(wwn) if login_obj not in dup_login: dup_login.append(login_obj) login_obj.s_add_alert( al.AlertTable.alertTbl, al.ALERT_NUM.LOGIN_DUP_LOGIN, None, brcddb_fabric.best_fab_name(fobj)) if len(dup_login) > dup_login_len: dup_login.append(None) return dup_login
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 """ global _DEBUG, __version__, _ZONE_CHECK # Get and validate user input inf, outf, sfp_rules, iocp, custom_parms = _get_input() ml = ['WARNING!!! Debug is enabled'] if _DEBUG else list() ml.append('report.py version ' + __version__) ml.append('In file: ' + inf) ml.append('Out file: ' + outf) ml.append('SFP rules file: ' + str(sfp_rules)) if sfp_rules is not None: ml.append("The 'User Warning: Data Validation ...' can be ignored.") brcddb_bp.sfp_rules = report_utils.parse_sfp_file(sfp_rules) ml.append('custom_parms: ' + str(custom_parms)) brcdapi_log.log(ml, True) # Get the project object try: proj_obj = brcddb_project.read_from(inf) except FileNotFoundError: brcdapi_log.log('Input file, ' + inf + ', not found', True) return brcddb_common.EXIT_STATUS_ERROR if proj_obj is None: return brcddb_common.EXIT_STATUS_ERROR # Perform all pre-processing (parse IOCPs, build references, ...) brcdapi_log.log('Building cross references', True) brcddb_project.build_xref(proj_obj) brcddb_project.add_custom_search_terms(proj_obj) brcdapi_log.log('Performing mainframe checks', True) for file in brcapi_file.read_directory(iocp): brcddb_iocp.parse_iocp(proj_obj, iocp + '/' + file) brcddb_bp.best_practice(al.AlertTable.alertTbl, proj_obj) if _ZONE_CHECK: for obj in proj_obj.r_fabric_objects( ): # Get a zone analysis on all fabrics brcdapi_log.log( 'Performing zone analysis for fabric ' + brcddb_fabric.best_fab_name(obj), True) brcddb_fabric.zone_analysis(obj) # Generate the report brcddb_report.report(proj_obj, outf) _custom_report(proj_obj, custom_parms) return brcddb_common.EXIT_STATUS_ERROR if proj_obj.r_is_any_error( ) else brcddb_common.EXIT_STATUS_OK
def replace_zoning(session, fab_obj, fid): """Replaces the zoning datbase in a fabric by clearing it and then PATCHing it with a new zoning database Relevant resource: 'zoning/defined-configuration' An error is returned if there is no zone database in in the fab_obj. Use clear_zoning() to clear out zoning. :param session: Login session object from brcdapi.brcdapi_rest.login() :type session: dict :param fab_obj: Fabric object whose zone database will be sent to the switch :type fab_obj: brcddb.classes.fabric.FabricObj :param fid: Fabric ID. If FID check is disabled, this must be the FID of the switch where the request is sent. :type fid: int :return: Object returned from FOS API :rtype: dict """ # Get the dict to be converted to JSON and sent to the switch content = build_all_zone_content(fab_obj) if content is None: return pyfos_auth.create_error( 400, 'No zone database in ' + brcddb_fabric.best_fab_name(obj.r_fabric_obj()), '') # Get the checksum - this is needed to save the configuration. checksum, obj = brcdapi_zone.checksum(session, fid, fab_obj) if pyfos_auth.is_error(obj): return obj # Clear the zone database obj = brcdapi_zone.clear_zone(session, fid) if not pyfos_auth.is_error(obj): # Send the zoning request obj = brcdapi_rest.send_request(session, 'brocade-zone/defined-configuration', 'PATCH', content, fid) if not pyfos_auth.is_error(obj): return brcdapi_zone.save(session, fid, checksum) # If we got this far, something went wrong so abort the transaction. brcdapi_zone.abort(session, fid) return obj
def bp_page(wb, tc, sheet_name, sheet_i, sheet_title, obj, display, display_tbl): """Creates a best practice violation 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 obj: Project or fabric object. :type obj: brcddb.classes.project.ProjectObj, brcddb.classes.fabric.FabricObj :param display: List of parameters to display. :type display: list, tuple :param display_tbl: Display control table. See brcddb.report.report_tables.display_tbl :rtype: None """ # Validate the user input err_msg = list() if obj is None: err_msg.append('obj was not defined.') elif not bool('ProjectObj' in str(type(obj)) or 'FabricObj' in str(type(obj))): err_msg.append('Invalid object type: ' + str(type(obj)) + '.') if display is None: err_msg.append('display not defined.') if len(err_msg) > 0: brcdapi_log.exception(err_msg, True) return # Create the worksheet, add the headers, and set up the column widths sheet = wb.create_sheet(index=sheet_i, title=sheet_name) sheet.page_setup.paperSize = sheet.PAPERSIZE_LETTER sheet.page_setup.orientation = sheet.ORIENTATION_LANDSCAPE col = 1 row = 1 if isinstance(tc, str): cell = xl.get_column_letter(col) + str(row) sheet[cell].hyperlink = '#' + tc + '!A1' sheet[cell].font = report_fonts.font_type('link') sheet[cell] = 'Contents' col += 1 cell = xl.get_column_letter(col) + str(row) sheet[cell].font = report_fonts.font_type('hdr_1') sheet[cell] = sheet_title sheet.freeze_panes = sheet['A3'] col = 1 row += 1 for k in display: if k in display_tbl and 'dc' in display_tbl[ k] and display_tbl[k]['dc'] is True: continue cell = xl.get_column_letter(col) + str(row) sheet[cell].font = report_fonts.font_type('bold') sheet[cell].border = report_fonts.border_type('thin') if k in display_tbl: if 'c' in display_tbl[k]: sheet.column_dimensions[xl.get_column_letter( col)].width = display_tbl[k]['c'] try: if display_tbl[k]['v']: sheet[cell].alignment = report_fonts.align_type( 'wrap_vert_center') else: sheet[cell].alignment = report_fonts.align_type('wrap') except: sheet[cell].alignment = report_fonts.align_type('wrap') if 'd' in display_tbl[k]: sheet[cell] = display_tbl[k]['d'] else: sheet[ cell] = k # This happens when a new key is introduced before the display tables have been updated else: sheet[ cell] = k # This happens when a new key is introduced before the display tables have been updated col += 1 # Get a list of fabric objects and initialize alert_list if 'ProjectObj' in str(type(obj)): fab_list = obj.r_fabric_objects() chassis_list = obj.r_chassis_objects() switch_list = obj.r_switch_objects() else: fab_list = [obj] chassis_list = obj.r_project_obj().r_chassis_objects() switch_list = obj.r_project_obj().r_switch_objects() alert_list = list() # Get all the chassis alerts for tobj in chassis_list: tl = list() for sev in (al.ALERT_SEV.ERROR, al.ALERT_SEV.WARN): # Display errors first tl.extend( _add_alerts(tobj, 'Chassis', sev, brcddb_chassis.best_chassis_name(tobj), '')) if len(tl) > 0: alert_list.append(['']) alert_list.append( ['Chassis: ' + brcddb_chassis.best_chassis_name(tobj)]) alert_list.extend(tl) # Get all the fabric alerts for fab_obj in fab_list: tl = list() for sev in (al.ALERT_SEV.ERROR, al.ALERT_SEV.WARN): # Display errors first tl.extend( _add_alerts(fab_obj, 'Fabric', sev, brcddb_fabric.best_fab_name(fab_obj), '')) for tobj in fab_obj.r_zonecfg_objects(): tl.extend( _add_alerts(tobj, 'ZoneCfg', sev, tobj.r_obj_key(), '')) for tobj in fab_obj.r_zone_objects(): tl.extend(_add_alerts(tobj, 'Zone', sev, tobj.r_obj_key(), '')) for tobj in fab_obj.r_alias_objects(): tl.extend(_add_alerts(tobj, 'Alias', sev, tobj.r_obj_key(), '')) for tobj in fab_obj.r_login_objects(): tl.extend(_add_alerts(tobj, 'Login', sev, tobj.r_obj_key(), '')) for tobj in fab_obj.r_fdmi_node_objects(): tl.extend( _add_alerts(tobj, 'FDMI_Node', sev, tobj.r_obj_key(), '')) for tobj in fab_obj.r_fdmi_port_objects(): tl.extend( _add_alerts(tobj, 'FDMI_Port', sev, tobj.r_obj_key(), '')) if len(tl) > 0: alert_list.append(['']) alert_list.append( ['Fabric: ' + brcddb_fabric.best_fab_name(fab_obj, True)]) alert_list.extend(tl) # Get all the switch and port alerts for switch_obj in switch_list: tl = list() for sev in (al.ALERT_SEV.ERROR, al.ALERT_SEV.WARN): # Display errors first tl.extend( _add_alerts(switch_obj, 'Switch', sev, brcddb_switch.best_switch_name(switch_obj), '')) for tobj in switch_obj.r_port_objects(): tl.extend( _add_alerts(tobj, 'Port', sev, brcddb_port.best_port_name(tobj), tobj.r_obj_key())) if len(tl) > 0: alert_list.append(['']) alert_list.append([ 'Switch: ' + brcddb_switch.best_switch_name(switch_obj, True) ]) alert_list.extend(tl) # Now add the alerts to the worksheet # Set up the cell formatting border = report_fonts.border_type('thin') alignment = report_fonts.align_type('wrap') font = report_fonts.font_type('std') # Add all alerts to the worksheet for x in alert_list: row += 1 col = 1 if len(x) == 0: row += 1 elif len(x) == 1: sheet.merge_cells(start_row=row, start_column=1, end_row=row, end_column=len(display)) cell = xl.get_column_letter(col) + str(row) sheet[cell].font = report_fonts.font_type('hdr_2') if len(x[0]) > 0: sheet[cell].fill = report_fonts.fill_type('lightblue') sheet[cell] = x[0] else: for k in display: cell = xl.get_column_letter(col) + str(row) sheet[cell].border = border sheet[cell].font = font sheet[cell].alignment = alignment sheet[cell] = bp_case[k](x) col += 1
def performance_dashboard(wb, tc, sheet_name, sheet_i, sheet_title, content): """Creates a dashboard 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 content: Caller defined content. List of lists or tuples to add to the title page. For example: dashboard = collections.OrderedDict() dashboard['class-3-discards'] = {'title' : 'Top 10 C3 Discards', 'port_list' : []} dashboard['in-crc-errors'] = {'title' : 'Top 10 CRC With Good EOF', 'port_list' : []} :type content: list, tuple :rtype: None """ hdr = collections.OrderedDict() # Key is the column header and value is the width hdr['Count'] = 14 hdr['Fabric'] = 22 hdr['Switch'] = 22 hdr['Port'] = 7 hdr['Type'] = 8 hdr['Description'] = 117 - (hdr['Count'] + hdr['Switch'] + hdr['Switch'] + hdr['Port'] + hdr['Type']) # Create the worksheet, add the title, and set up the column widths sheet = wb.create_sheet(index=sheet_i, title=sheet_name) sheet.page_setup.paperSize = sheet.PAPERSIZE_LETTER sheet.page_setup.orientation = sheet.ORIENTATION_LANDSCAPE col = 1 row = 1 for k, v in hdr.items(): sheet.column_dimensions[xl.get_column_letter(col)].width = v col += 1 max_col = col - 1 col = 1 if isinstance(tc, str): cell = xl.get_column_letter(col) + str(row) sheet[cell].hyperlink = '#' + tc + '!A1' sheet[cell].font = report_fonts.font_type('link') sheet[cell] = 'Contents' col += 1 cell = xl.get_column_letter(col) + str(row) sheet.merge_cells(start_row=row, start_column=col, end_row=row, end_column=max_col) sheet[cell].font = report_fonts.font_type('hdr_1') sheet[cell] = sheet_title row += 2 # Now add each dashboard item border = report_fonts.border_type('thin') font = report_fonts.font_type('std') alignment = report_fonts.align_type('wrap') for statistic in content.keys(): db = content.get(statistic) col = 1 # The individual dashboard title sheet.merge_cells(start_row=row, start_column=1, end_row=row, end_column=max_col) for i in range(col, max_col + 1): cell = xl.get_column_letter(i) + str(row) sheet[cell].border = border cell = xl.get_column_letter(col) + str(row) sheet[cell].font = report_fonts.font_type('hdr_2') sheet[cell].fill = report_fonts.fill_type('lightblue') sheet[cell] = db.get('title') col = 1 row += 1 # Now the individual dashboard headers for k in hdr.keys(): cell = xl.get_column_letter(col) + str(row) sheet[cell].border = border sheet[cell].font = report_fonts.font_type('bold') sheet[cell] = k col += 1 # Now add the dashboard content port_list = db.get('port_list') if len(port_list) == 0: row += 1 for port_obj in port_list: # Statistic col = 1 cell = xl.get_column_letter(col) + str(row) sheet[cell].border = border sheet[cell].font = font sheet[cell].alignment = alignment sheet[cell] = port_obj.r_get('fibrechannel-statistics/' + statistic) col += 1 # Fabric cell = xl.get_column_letter(col) + str(row) sheet[cell].border = border sheet[cell].font = font sheet[cell].alignment = alignment sheet[cell] = brcddb_fabric.best_fab_name( port_obj.r_switch_obj().r_fabric_obj()) col += 1 # Switch cell = xl.get_column_letter(col) + str(row) sheet[cell].border = border sheet[cell].font = font sheet[cell].alignment = alignment sheet[cell] = brcddb_switch.best_switch_name( port_obj.r_switch_obj()) col += 1 # Port cell = xl.get_column_letter(col) + str(row) sheet[cell].border = border sheet[cell].font = font sheet[cell].alignment = alignment sheet[cell] = port_obj.r_obj_key() col += 1 # Port Type cell = xl.get_column_letter(col) + str(row) sheet[cell].border = border sheet[cell].font = font sheet[cell].alignment = alignment sheet[cell] = port_obj.c_login_type() col += 1 # Description - Try FDMI first, then name server cell = xl.get_column_letter(col) + str(row) sheet[cell].border = border sheet[cell].font = font sheet[cell].alignment = alignment sheet[cell] = brcddb_port.port_best_desc(port_obj) row += 1 row += 1
def _fabric_ts(o, k): obj = o.r_fabric_obj(k) return brcddb_fabric.best_fab_name(obj, True), brcddb_fabric.best_fab_name( obj, False)
def _fabric_name(p_obj, wwn, flag=True): return brcddb_fabric.best_fab_name(p_obj.r_fabric_obj(wwn), flag)
def report(proj_obj, outf, remove_pages=None, add_pages=None): """Creates an Excel report. Sort of a SAN Health like report. :param proj_obj: Project object :type proj_obj: brcddb.classes.project.ProjectObj :param outf: Output file name :type outf: str :param remove_pages: List of default pages to remove. Done first so you can clear all then add pages. :type remove_pages: None, str, list :param add_pages: Pages, in addition to the defaults, to add to the report :type add_pages: None, str, list """ global _report_pages # Figure out what pages to include in the report for key in brcddb_util.convert_to_list(remove_pages): d = _report_pages.get(key) if d is None: if key == 'all': for obj in _report_pages.values(): obj['s'] = False break else: brcdapi_log.log(key + ' is unkonwn in remove page list. ignored') else: d['s'] = False for key in brcddb_util.convert_to_list(add_pages): d = _report_pages.get(key) if d is None: if key == 'all': for obj in _report_pages.values(): obj['s'] = True break else: brcdapi_log.log(key + ' is unkonwn in add page list. ignored') else: d['s'] = True """port_pages is used to determine how to display pages +-------+-------------------------------------------------------------------------------+ | key | Description | +=======+===============================================================================+ | c | Key in the _report_pages table | +-------+-------------------------------------------------------------------------------+ | s | Sheet name prefix | +-------+-------------------------------------------------------------------------------+ | sc | Number of columns to skip | +-------+-------------------------------------------------------------------------------+ | t | The table used to control how the port data is displayed. | +-------+-------------------------------------------------------------------------------+ | d | Text to display as a header on the worksheet. | +-------+-------------------------------------------------------------------------------+ | l | When true, displays all the logins. Otherwise, just the base WWN is reported. | +-------+-------------------------------------------------------------------------------+ """ port_pages = [ dict(c='port_config', sc=1, s='_config', t=rt.Port.port_config_tbl, d='Port Configurations', l=False), dict(c='port_config_error', sc=1, s='_config_error', t=rt.Port.port_config_tbl, d='Port Configurations Error Summary', l=False), dict(c='port_stats', sc=1, s='_stats', t=rt.Port.port_stats_tbl, d='Port Statistics', l=False), dict(c='port_stats_error', sc=1, s='_stats_error', t=rt.Port.port_stats_tbl, d='Port Statistics Error Summary', l=False), dict(c='port_zone', sc=1, s='_zl', t=rt.Port.port_zone_tbl, d='Ports by Zone and Login', l=True), dict(c='port_zone_error', sc=1, s='_zl_error', t=rt.Port.port_zone_tbl, d='Ports by Zone and Login Error Summary', l=True), dict(c='port_sfp', sc=1, s='_sfp', t=rt.Port.port_sfp_tbl, d='SFP report', l=False), dict(c='port_sfp_error', sc=1, s='_sfp_error', t=rt.Port.port_sfp_tbl, d='SFP Error Summary', l=False), dict(c='port_rnid', sc=1, s='_ficon', t=rt.Port.port_rnid_tbl, d='Port RNID data', l=False), ] # tc_page = report_utils.valid_sheet_name.sub('', proj_obj.r_obj_key())[:29] + '_xx' tc_page = 'Table_of_Contents' tbl_contents = list() # Set up the workbook sheet_index = 0 wb = report_utils.new_report() # Check project for duplicate WWNs tbl_contents.append(dict(h=True, d='Duplicate WWNs')) wl = brcddb_project.dup_wwn(proj_obj) if len(wl) > 0: sname = 'dup_wwns' report_login.login_page(wb, tc_page, sname, sheet_index, 'Duplicate WWNs', wl, dup_login_tbl, rt.Login.login_display_tbl, False) tbl_contents.append(dict(sc=1, s=sname, d='Duplicate WWNs')) sheet_index += 1 else: tbl_contents.append(dict(sc=1, d='No Duplicate WWNs Found')) # Project dashboard if _report_pages['proj_dashboard']['s']: tbl_contents.append(dict(h=True, d='Project Links')) sname = 'proj_dashboard' title = 'Project Dashboard' dashboard(proj_obj, tc_page, wb, sheet_index, sname, title) tbl_contents.append(dict(sc=1, s=sname, d=title)) sheet_index += 1 # Add all the chassis if _report_pages['chassis']['s']: tbl_contents.append(dict(h=True, d='Chassis')) for chassis_obj in proj_obj.r_chassis_objects(): chassis_name = brcddb_chassis.best_chassis_name(chassis_obj) brcdapi_log.log('Processing chassis: ' + chassis_name, True) sname = report_utils.valid_sheet_name.sub( '', chassis_name.replace(' ', '_'))[:22] + '_' + str(sheet_index) report_chassis.chassis_page(wb, tc_page, sname, sheet_index, 'Chassis Detail For: ' + chassis_name, chassis_obj, rt.Chassis.chassis_display_tbl) tbl_contents.append(dict(sc=1, s=sname, d=chassis_name)) sheet_index += 1 # Add all the fabrics for fab_obj in proj_obj.r_fabric_objects(): fab_name = brcddb_fabric.best_fab_name(fab_obj) if len(fab_name) == 0: fab_name = 'Unknown Fabric' brcdapi_log.log('Processing fabric: ' + fab_name, True) tbl_contents.append(dict(h=True, d=fab_name)) prefix = report_utils.valid_sheet_name.sub( '', fab_name.replace(' ', '_'))[:20] + '_' + str(sheet_index) # Fabric summary page if _report_pages['fabric_summary']['s']: brcdapi_log.log(' Building fabric summary page', True) sname = prefix + '_sum' report_fabric.fabric_page(wb, tc_page, sheet_index, sname, fab_name + ' Summary', fab_obj) tbl_contents.append(dict(sc=1, s=sname, d='Fabric Summary')) sheet_index += 1 # Fabric Dashboard if _report_pages['fabric_dashboard']['s']: brcdapi_log.log(' Building fabric dashboard', True) sname = prefix + '_db' dashboard(fab_obj, tc_page, wb, sheet_index, sname, fab_name + ' Dasboard') tbl_contents.append(dict(sc=1, s=sname, d='Fabric Dashboard')) sheet_index += 1 # Switch page if _report_pages['switch']['s']: brcdapi_log.log(' Building switch detail page', True) sname = prefix + '_switch' report_switch.switch_page(wb, tc_page, sname, sheet_index, 'Switch Detail For Fabric: ' + fab_name, fab_obj.r_switch_objects(), rt.Switch.switch_display_tbl) tbl_contents.append(dict(sc=1, s=sname, d='Switch Detail')) sheet_index += 1 # Now the port pages brcdapi_log.log(' Building the port pages', True) port_list = brcddb_util.sort_ports(fab_obj.r_port_objects()) for obj in port_pages: if _report_pages[obj['c']]['s']: sname = prefix + obj.get('s') report_port.port_page(wb, tc_page, sname, sheet_index, fab_name + ' ' + obj.get('d'), port_list, obj.get('t'), rt.Port.port_display_tbl, obj.get('l')) tbl_contents.append(dict(sc=1, s=sname, d=obj.get('d'))) sheet_index += 1 # Zone Analysis Page if _report_pages['zone_page']['s']: brcdapi_log.log(' Building zone analysis page', True) sname = prefix + '_zone' report_zone.zone_page(fab_obj, tc_page, wb, sname, sheet_index, fab_name + ' Zone Analysis') tbl_contents.append(dict(sc=1, s=sname, d='Zone Analysis')) sheet_index += 1 # Taget Zone Page if _report_pages['t_zone_page']['s']: brcdapi_log.log(' Building target zone page', True) sname = prefix + '_tzone' report_zone.target_zone_page(fab_obj, tc_page, wb, sname, sheet_index, fab_name + ' Zone by Target') tbl_contents.append(dict(sc=1, s=sname, d='Zone by Target')) sheet_index += 1 # Alias Page if _report_pages['alias']['s']: brcdapi_log.log(' Building alias page', True) sname = prefix + '_alias' report_zone.alias_page(fab_obj, tc_page, wb, sname, sheet_index, fab_name + ' Alias Detail') tbl_contents.append(dict(sc=1, s=sname, d='Alias Detail')) sheet_index += 1 # Login Page if _report_pages['login']['s']: brcdapi_log.log(' Building login page', True) sname = prefix + '_login' report_login.login_page(wb, tc_page, sname, sheet_index, fab_name + ' Logins', fab_obj.r_login_objects(), rt.Login.login_tbl, rt.Login.login_display_tbl, True) tbl_contents.append(dict(sc=1, s=sname, d='Logins')) sheet_index += 1 # IOCP Page if _report_pages['iocp']['s']: iocp_objects = proj_obj.r_iocp_objects() if len(iocp_objects) > 0: brcdapi_log.log('Adding the IOCP pages', True) tbl_contents.append(dict(h=True, d='IOCPs')) for iocp_obj in iocp_objects: sname = report_utils.valid_sheet_name.sub( '', iocp_obj.r_obj_key())[:22] report_iocp.iocp_page(iocp_obj, tc_page, wb, sname, sheet_index, sname) tbl_contents.append(dict(sc=1, s=sname, d=sname)) sheet_index += 1 # Add the Best Practice page if _report_pages['bp']['s']: sname = 'Best_Practice' fab_name = 'Best Practice Violations' # Just borrowing fab_name for the title report_bp.bp_page(wb, tc_page, sname, 0, fab_name, proj_obj, rt.BestPractice.bp_tbl, rt.BestPractice.bp_display_tbl) tbl_contents.insert(0, dict(sc=1, s=sname, d=fab_name)) tbl_contents.insert(0, dict(h=True, d=fab_name)) # Add the missing chassis (chassis not polled) to the title & contents page i = 0 tbl_contents.append( dict(h=True, merge=3, d='Missing chassis (discovered in fabrics but not polled)')) for chassis_obj in proj_obj.r_chassis_objects(): if chassis_obj.r_get('brocade-chassis') is None: # Try to find a chassis name chassis_name = None for obj in chassis_obj.r_switch_objects(): chassis_name = obj.r_get( 'brocade-fabric/fabric-switch/chassis-user-friendly-name') if chassis_name is not None: break if chassis_name is None: chassis_name = 'Unknown' chassis_name += ' (' + chassis_obj.r_obj_key( ) + '). Known logical switches:' tbl_contents.append(dict(sc=1, d=chassis_name)) for obj in chassis_obj.r_switch_objects(): tbl_contents.append( dict(sc=2, d=brcddb_switch.best_switch_name(obj, True))) i += 1 if i == 0: tbl_contents.append(dict(sc=1, d='None')) # Insert the title & contents page proj_title_page(proj_obj, None, wb, 0, tc_page, 'Contents', contents=tbl_contents) # Save the report. report_utils.save_report(wb, outf)
def _merge_zone_db(proj_obj, new_zone_cfg, a_flag): """Merges the zones for the fabrics specified in fab_csv :param proj_obj: Project object :type proj_obj: brcddb.classes.project.ProjectObj :param new_zone_cfg: Name of zone configuration to add :type new_zone_cfg: str, None :param a_flag: If True, make new_zone_cfg the effective zone configuration :type a_flag: bool :return rl: Error message list. If empty, no errors encountered :rtype rl: list """ rl = list() # Find a fabric to start with, base_fab_obj, and get a list of the remaining fabrics to add to it. fab_l = list() base_fab_obj = None new_zonecfg_obj = None for fab_obj in proj_obj.r_fabric_objects(): zd = fab_obj.r_get( 'zone_merge' ) # zd should never be None. This is just future proofing. if zd is None or zd.get('fab_wwn') is None: continue if base_fab_obj is None: base_fab_obj = brcddb_fabric.copy_fab_obj(fab_obj, fab_key=None, full_copy=False) if isinstance(new_zone_cfg, str): mem_l = list() if isinstance(zd['cfg'], str): zonecfg_obj = fab_obj.r_zonecfg_obj(zd['cfg']) if zonecfg_obj is None: rl.append( 'Could not find ' + zd['cfg'] + ' in ' + brcddb_fabric.best_fab_name(fab_obj, wwn=True)) else: mem_l = zonecfg_obj.r_members() if isinstance(new_zone_cfg, str): new_zonecfg_obj = base_fab_obj.s_add_zonecfg( new_zone_cfg, mem_l) brcddb_util.add_to_obj(proj_obj, 'zone_merge/base_fab_obj', base_fab_obj) else: fab_l.append(fab_obj) if base_fab_obj is None: rl.append( 'Could not find a fabric containing any of the specified zone configurations.' ) if len(fab_l) < 1: rl.append('Could not find any fabrics to merge. Must have at least 2.') if len(rl) > 0: return rl # Merge the individual zone items for fab_obj in fab_l: change_count, change_d = brcddb_compare.compare( base_fab_obj, fab_obj, brcddb_control_tbl=_control_tables) for local_key, action in _merge_case.items(): rl.extend(action(change_d.get(local_key), base_fab_obj, fab_obj)) # Add the zones to the merged zone configuration zd = fab_obj.r_get( 'zone_merge' ) # zd should never be None. This is just future proofing. if new_zonecfg_obj is None or zd is None or zd.get('cfg') is None: continue add_zonecfg_obj = fab_obj.r_zonecfg_obj(zd.get('cfg')) if add_zonecfg_obj is not None: new_zonecfg_obj.s_add_member(add_zonecfg_obj.r_members()) # If the new zone configuration is to be enabled, set it as the effective zone configuration if a_flag: base_fab_obj.s_del_eff_zonecfg() base_fab_obj.s_add_eff_zonecfg(new_zonecfg_obj.r_members()) return rl
def _patch_zone_db(proj_obj, eff_cfg): """Replaces the zoning in the fabric(s). :param proj_obj: Project object :type proj_obj: brcddb.classes.project.ProjectObj :param eff_cfg: Name of zone configuration to activate. None if no zone configuration to activate. :type eff_cfg: str, None :return: List of error messages. Empty list if no errors found :rtype: list() """ rl = list() # List of error messages to return base_fab_obj = proj_obj.r_get('zone_merge/base_fab_obj') if base_fab_obj is None: rl.append( 'base_fab_obj is None') # There is a code bug if this happens return rl update_count = 0 for fab_obj in proj_obj.r_fabric_objects(): # Get the login credentials ip_addr = fab_obj.r_get('zone_merge/ip') id = fab_obj.r_get('zone_merge/id') pw = fab_obj.r_get('zone_merge/pw') sec = fab_obj.r_get('zone_merge/sec') fid = fab_obj.r_get('zone_merge/fid') update = fab_obj.r_get('zone_merge/update') if ip_addr is None or id is None or pw is None or sec is None or fid is None or update is None or not update: continue # Login session = api_int.login(id, pw, ip_addr, sec, proj_obj) if fos_auth.is_error(session): rl.append(fos_auth.formatted_error_msg(session)) return rl # Send the changes to the switch brcdapi_log.log( 'Sending zone updates to ' + brcddb_fabric.best_fab_name(fab_obj, wwn=True), True) try: obj = api_zone.replace_zoning(session, base_fab_obj, fid) if fos_auth.is_error(obj): rl.append(fos_auth.formatted_error_msg(obj)) else: update_count += 1 if isinstance(eff_cfg, str): obj = api_zone.enable_zonecfg(session, None, fid, eff_cfg) if fos_auth.is_error(obj): rl.append(fos_auth.formatted_error_msg(obj)) except: rl.append('Software fault in api_zone.replace_zoning()') # Logout obj = brcdapi_rest.logout(session) if fos_auth.is_error(obj): rl.append(fos_auth.formatted_error_msg(obj)) brcdapi_log.log(str(update_count) + ' switch(es) updated.', True) return rl