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 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, sec, log, nl = parse_args() if sec is None: sec = 'none' if not nl: brcdapi_log.open_log(log) 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) brcdapi_log.log(ml, True) # Login brcdapi_log.log('Attempting login', True) session = brcdapi_rest.login(user_id, pw, ip, sec) if brcdapi_auth.is_error(session): brcdapi_log.log('Login failed. Error message is:', True) brcdapi_log.log(brcdapi_auth.formatted_error_msg(session), True) return -1 # Logout brcdapi_log.log('Login succeeded. Attempting logout', True) obj = brcdapi_rest.logout(session) if brcdapi_auth.is_error(obj): brcdapi_log.log('Logout failed. Error message is:', True) brcdapi_log.log(brcdapi_auth.formatted_error_msg(obj), True) return -1 brcdapi_log.log('Logout succeeded.', True) return 1
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 _convert_ip_addr(obj): if isinstance(obj, dict): d = dict() for k, v in obj.items(): d.update({k: _convert_ip_addr(v)}) return d elif isinstance(obj, (list, tuple)): return [_convert_ip_addr(v) for v in obj] else: return brcdapi_util.mask_ip_addr(obj)
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 get_batch(session, proj_obj, kpi_list, fid=None): """Processes a batch API requests. All chassis request are performed first, followed by processing of fid_rest_data If any warnings or errors are encountered, the log is updated and the appropriate flag bits for the proj_obj are set. Search for _project_warn in brcddb_common.py for additional information. Again, search for _project_warn in brcddb.classes for object methods to set and check these bits. :param session: Session object, or list of session objects, returned from brcdapi.pyfos_auth.login() :type session: dict :param proj_obj: Project object :type proj_obj: brcddb.classes.ProjectObj :param kpi_list: List of KPIs to request from the switches and chassis :type kpi_list: list :param fid: FID, or list of FIDs for logical switch level requests. If None, execute requests for all FIDs. :type fid: int, list, tuple, None :rtype: None """ # Get the chassis object chassis_obj = get_chassis(session, proj_obj) if chassis_obj is None: brcdapi_log.log(brcdapi_util.mask_ip_addr(session.get('ip_addr')) + 'Chassis not found.', True) return kl = brcddb_util.convert_to_list(kpi_list) # Get all the chassis data for kpi in [kpi for kpi in kl if not brcdapi_util.uri_map[kpi]['fid']]: results_action(chassis_obj, get_rest(session, kpi, chassis_obj), kpi) # Figure out which logical switches to poll switch level data from. if chassis_obj.r_is_vf_enabled() and fid is not None: switch_list = list() for fab_id in brcddb_util.convert_to_list(fid): switch_obj = chassis_obj.r_switch_obj_for_fid(fab_id) if switch_obj is None: brcdapi_log.log('FID ' + str(fab_id) + ' not found', True) else: switch_list.append(switch_obj) else: switch_list = chassis_obj.r_switch_objects() # Now process all the switch (FID) level commands. for switch_obj in switch_list: for kpi in [kpi for kpi in kl if brcdapi_util.uri_map[kpi]['fid']]: results_action(switch_obj, get_rest(session, kpi, switch_obj, brcddb_switch.switch_fid(switch_obj)), kpi)
def _process_errors(session, uri, obj, wobj): """Checks for errors in the API response and adds alerts to the object if there is an error :param session: Session object returned from brcdapi.pyfos_auth.login() :type session: dict :param uri: URI, less the prefix :type uri: str :param obj: FOS API object :type obj: dict :param wobj: The brcddb class object we were working when the error occured :type wobj: brcddb.classes.project.ProjectObj, brcddb.classes.chassis.ChassisObj, brcddb.classes.switch.SwitchObj,\ None """ if not pyfos_auth.is_error(obj): return ip_addr = brcdapi_util.mask_ip_addr(session.get('ip_addr')) p1 = pyfos_auth.formatted_error_msg(obj) brcdapi_log.log(ip_addr + " Request FAILED:\n" + p1, True) if wobj is None: return proj_obj = wobj.r_project_obj() proj_obj.s_api_error_flag() error_table = dict( ProjectObj=dict( p0=ip_addr, al_num=al.ALERT_NUM.PROJ_FAILED_LOGIN if '/rest/login' in uri else al.ALERT_NUM.PROJ_CHASSIS_API_ERROR ), ChassisObj=dict(p0=brcddb_chassis.best_chassis_name(wobj), al_num=al.ALERT_NUM.PROJ_CHASSIS_API_ERROR), SwitchObj=dict(p0=brcddb_switch.best_switch_name(wobj), al_num=al.ALERT_NUM.PROJ_SWITCH_API_ERROR) ) simple_type = brcddb_class_util.get_simple_class_type(wobj) if simple_type in error_table: p0 = error_table[simple_type]['p0'] al_num = error_table[simple_type]['al_num'] else: brcdapi_log.exception('Unknown object type: ' + str(type(wobj))) return proj_obj.s_add_alert(al.AlertTable.alertTbl, al_num, None, p0, p1)
def _get_input(): """Retrieves the command line input, reads the input Workbook, and validates the input :return ec: Error code from brcddb.brcddb_common :rtype ec: int :return sl: List of switches to poll as read from the input Workbook :rtype sl: list :return pl: List of project files to combine :rtype pl: list :return cfg_name: Name of zone configuration file to create :rtype cfg_name: str, None :return a_cfg: Activation flag. If True, activate the zone configuration specified by cfg_name :rtype a_cfg: bool :return t_flag: Test flag. If True, test only. Do not make any changes :rtype t_flag: bool :return scan_flag: Scan flag. If True, scan files and switches for fabric information :rtype scan_flag: bool :return addl_parms: Additional parameters (logging and debug flags) to pass to multi_capture.py :rtype addl_parms: list """ global _DEBUG, __version__ # Initialize the return variables ec = brcddb_common.EXIT_STATUS_OK addl_parms = list() # Get and validate the user input ip, user_id, pw, sec, fid, cfile, wwn, a_flag, scan_flag, d_flag, s_flag, log, nl = parse_args( ) if s_flag: addl_parms.append('-sup') brcdapi_log.set_suppress_all() if nl: addl_parms.append('-nl') else: brcdapi_log.open_log(log) if log is not None: addl_parms.extend(['-log', log]) if d_flag: addl_parms.append('-d') brcdapi_rest.verbose_debug = True buf = '' if isinstance(fid, int): buf = ' INVALID. Must be an integer in the range of 1-128' if fid < 0 or fid > 128 else '' ml = ['WARNING!!! Debug is enabled'] if _DEBUG else list() ml.append('zone_merge.py version: ' + __version__) ml.append('IP address: ' + brcdapi_util.mask_ip_addr(ip)) ml.append('ID: ' + str(user_id)) ml.append('HTTPS: ' + str(sec)) ml.append('FID: ' + str(fid) + buf) ml.append('Input file: ' + cfile) ml.append('WWN: ' + str(wwn)) ml.append('Activate zone cfg: ' + str(a_flag)) ml.append('Scan: ' + str(scan_flag)) brcdapi_log.log(ml, True) if len(buf) > 0: return brcddb_common.EXIT_STATUS_INPUT_ERROR if sec is None: sec = 'none' ml = list() if not scan_flag: if ip is None: ml.append(' IP address (-ip)') if user_id is None: ml.append(' User ID (-id)') if pw is None: ml.append(' Password (-pw)') if fid is None: ml.append(' FID (-fid)') if len(buf) > 0: ml.append(' FID ' + buf) if wwn is None: ml.append(' Fabric WWN (-wwn)') if len(ml) > 0: ml.insert(0, 'Missing the following required parameters:') ml.append('Use the -h option for additional help.') brcdapi_log.log(ml, True) ec = brcddb_common.EXIT_STATUS_INPUT_ERROR return ec, ip, user_id, pw, sec, scan_flag, fid, cfile, wwn, a_flag, scan_flag, addl_parms
def _get_input(): """Parses the module load command line, performs basic parameter validation checks, and sets up the log file. :return ip_addr: IP address of switch :rtype ip_addr: str :return user_id: User login ID :rtype user_id: str :return pw: Login password :rtype pw: str :return sec: 'self' for self signed certificate (HTTPS) or 'none' (HTTP) :rtype sec: str """ global _DEBUG_ip, _DEBUG_id, _DEBUG_pw, _DEBUG_s, _DEBUG_d, _DEBUG_log, _DEBUG_nl if _DEBUG: args_ip, args_id, args_pw, args_s, args_d, args_log, args_nl = \ _DEBUG_ip, _DEBUG_id, _DEBUG_pw, _DEBUG_s, _DEBUG_d, _DEBUG_log, _DEBUG_nl else: buf = 'Displays the results from GET running/brocade-security/security-certificate. In addition to security '\ 'certificates, this URL also returns CSRs. Usually, this done to validate certificates so the CSRs '\ 'would be filtered out or ignored.' parser = argparse.ArgumentParser(description=buf) parser.add_argument('-ip', help='(Required) IP address', required=True) parser.add_argument('-id', help='(Required) User ID', required=True) parser.add_argument('-pw', help='(Required) Password', required=True) parser.add_argument( '-s', help="(Optional) Default is HTTP. Use self for HTTPS mode.", required=False) buf = '(Optional) Enable debug logging. Prints the formatted data structures (pprint) to the log and console.' parser.add_argument('-d', help=buf, action='store_true', required=False) buf = '(Optional) Directory where log file is to be created. Default is to use the current directory. The log' \ ' file name will always be "Log_xxxx" where xxxx is a time and date stamp.' parser.add_argument( '-log', help=buf, required=False, ) buf = '(Optional) No parameters. When set, a log file is not created. The default is to create a log file.' parser.add_argument('-nl', help=buf, action='store_true', required=False) args = parser.parse_args() args_ip, args_id, args_pw, args_s, args_d, args_log, args_nl = \ args.ip, args.id, args.pw, args.s, args.d, args.log, args.nl # Set up the log file if not args_nl: brcdapi_log.open_log(args_log) if args_d: # Verbose debug brcdapi_rest.verbose_debug = True # Condition the input if args_s is None: args_s = 'none' # User feedback about input. ml = ['WARNING: Debug mode is enabled'] if _DEBUG else list() ml.extend([ 'IP, -ip: ' + brcdapi_util.mask_ip_addr(args_ip, True), 'ID, -id: ' + args_id, 'Security, -sec: ' + args_s, '' ]) brcdapi_log.log(ml, True) return args_ip, args_id, args_pw, args_s
def _get_input(): """Parses the module load command line :return ec: Error code. 0: OK, -1: Errors encountered :rtype ec: int :return ip: Switch IP address :rtype ip: str :return id: User ID :rtype id: str :return pw: User password :rtype ip: str :return sec: Secure method. None for HTTP, otherwise the certificate or 'self' if self signed :rtype sec: str, None :return content: Content for "running/brocade-chassis/management-interface-configuration". :rtype content: dict """ global _DEBUG_ip, _DEBUG_id, _DEBUG_pw, _DEBUG_s, _DEBUG_r, _DEBUG_rest_en, _DEBUG_rest_dis global _DEBUG_https_en, _DEBUG_https_dis, _DEBUG_max_rest, _DEBUG_ka_en, _DEBUG_ka_en global _DEBUG_d, _DEBUG_log, _DEBUG_nl ec = 0 if _DEBUG: args_ip, args_id, args_pw, args_s = _DEBUG_ip, _DEBUG_id, _DEBUG_pw, 'none' if _DEBUG_s is None else _DEBUG_s args_rest_en, args_rest_dis, args_https_en, args_https_dis = \ _DEBUG_rest_en, _DEBUG_rest_dis, _DEBUG_https_en, _DEBUG_https_dis args_max_rest, args_ka_en, args_ka_dis = \ _DEBUG_max_rest, _DEBUG_ka_en, _DEBUG_ka_dis args_d, args_log, args_nl = _DEBUG_d, _DEBUG_log, _DEBUG_nl else: buf = 'Useful as a programming example only on how to read and make chassis configuration changes via the '\ '"running/brocade-chassis/management-interface-configuration" URI. If the only input is the login '\ 'credentials, the parameters are displayed and no other action taken.' parser = argparse.ArgumentParser(description=buf) parser.add_argument('-ip', help='(Required) IP address', required=True) parser.add_argument('-id', help='(Required) User ID', required=True) parser.add_argument('-pw', help='(Required) Password', required=True) parser.add_argument( '-s', help='(Optional) Default is HTTP. CA or "self" for HTTPS mode.', required=False) parser.add_argument( '-rest_en', help='(Optional) No parameters. Enables the Rest interface', action='store_true', required=False) parser.add_argument( '-rest_dis', help='(Optional) No parameters. Disables the Rest interface', action='store_true', required=False) parser.add_argument('-https_en', help='(Optional) No parameters. Enable HTTPS', action='store_true', required=False) parser.add_argument('-https_dis', help='(Optional) No parameters. Disable HTTPS', action='store_true', required=False) parser.add_argument( '-max_rest', help= '(Optional) Set the maximum number of REST sessions. Valid options are 1-10', required=False) parser.add_argument('-ka_en', help='(Optional) No parameters. Enable keep-alive', action='store_true', required=False) parser.add_argument('-ka_dis', help='(Optional) No parameters. Enable keep-alive', action='store_true', required=False) buf = '(Optional) Enable debug logging. Prints the formatted data structures (pprint) to the log and console.' parser.add_argument('-d', help=buf, action='store_true', required=False) buf = '(Optional) Directory where log file is to be created. Default is to use the current directory. The log' \ ' file name will always be "Log_xxxx" where xxxx is a time and date stamp.' parser.add_argument( '-log', help=buf, required=False, ) buf = '(Optional) No parameters. When set, a log file is not created. The default is to create a log file.' parser.add_argument('-nl', help=buf, action='store_true', required=False) args = parser.parse_args() args_ip, args_id, args_pw, args_s = args.ip, args.id, args.pw, 'none' if args.s is None else args.s args_rest_en, args_rest_dis, args_https_en, args_https_dis = \ args.rest_en, args.rest_dis, args.https_en, args.https_dis args_max_rest, args_ka_en, args_ka_dis = args.max_rest, args.ka_en, args.ka_dis args_d, args_log, args_nl = args.d, args.log, args.nl # Set up the log file if not args_nl: brcdapi_log.open_log(args_log) if args_d: # Verbose debug brcdapi_rest.verbose_debug = True rd = { 'rest-enabled': True if args_rest_en else False if args_rest_dis else None, 'https-protocol-enabled': True if args_https_en else False if args_https_dis else None, 'max-rest-sessions': args_max_rest, 'https-keep-alive-enabled': True if args_ka_en else False if args_ka_dis else None } # User feedback ml = ['WARNING!!! Debug is enabled'] if _DEBUG else list() ml.append('IP, -ip: ' + brcdapi_util.mask_ip_addr(args_ip, True)) ml.append('ID, -id: ' + args_id) ml.append('Security, -s: ' + args_s) ml.append('Enable Rest, -rest_en: ' + str(args_rest_en)) ml.append('Disable Rest, -rest_dis: ' + str(args_rest_dis)) ml.append('Enable HTTPS, -https_en: ' + str(args_https_en)) ml.append('Disable HTTPS, -https_en: ' + str(args_https_dis)) ml.append('Enable keep-alive, -ka_en: ' + str(args_ka_en)) ml.append('Disable keep-alive, -ka_dis: ' + str(args_ka_dis)) ml.append('Max Rest sessions, -max_rest: ' + str(args_max_rest)) # Validate the input and set up the return dictionary if args_rest_en and args_rest_dis: ml.append('-rest_en and -rest_dis are mutually exclusive.') ec = -1 if args_https_en and args_https_dis: ml.append('-https_en and -https_dis are mutually exclusive.') ec = -1 if args_ka_en and args_ka_dis: ml.append('-ka_en and -ka_dis are mutually exclusive.') ec = -1 if len(rd) == 0: ml.extend(['', 'No changes']) brcdapi_log.log(ml, True) return ec, args_ip, args_id, args_pw, args_s, rd
def pseudo_main(): """Basically the main(). :return: Exit code :rtype: int """ global _DEBUG # Get and validate command line input. ec = brcddb_common.EXIT_STATUS_OK ml = ['WARNING!!! Debug is enabled'] if _DEBUG else list() ip, user_id, pw, sec, file, force, s_flag, echo, vd, 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' file = brcdapi_file.full_file_name(file, '.xlsx') if ip is not None: if user_id is None: ml.append('Missing user ID, -id') ec = brcddb_common.EXIT_STATUS_INPUT_ERROR if pw is None: ml.append('Missing password, -pw') ec = brcddb_common.EXIT_STATUS_INPUT_ERROR ml.append('File: ' + file) ml.append( 'IP address: ' + brcdapi_util.mask_ip_addr(ip) if isinstance(ip, str) else str(ip)) ml.append('ID: ' + str(user_id)) ml.append('sec: ' + sec) if len(ml) > 0: brcdapi_log.log(ml, True) if ec != brcddb_common.EXIT_STATUS_OK: return ec echo = False if echo is None else echo # Read in the Workbook, generate the portaddress --bind commands, and configure the switch(es) switch_d_list = [ switch_d for switch_d in report_utils.parse_switch_file(file).values() ] session = proj_obj = None try: for switch_d in switch_d_list: switch_d.update(err_msgs=list()) # Create the bind commands if switch_d['bind']: _bind_commands(switch_d) cli_l = switch_d['bind_commands'].copy() i = 0 while i < len(cli_l): cli_l.insert(i, '') i += 16 cli_l.insert( 0, '\n# Bind commands for FID ' + str(switch_d['fid'])) cli_l.append('\n# End bind commands for FID ' + str(switch_d['fid'])) brcdapi_log.log(cli_l, True) # Create the logical switch if ip is not None and switch_d['switch_flag']: if session is None: # Login session = api_int.login(user_id, pw, ip, sec, proj_obj) if fos_auth.is_error(session): return brcddb_common.EXIT_STATUS_API_ERROR if proj_obj is None: # Create a project object proj_obj = brcddb_project.new( 'Create_LS', datetime.datetime.now().strftime('%d %b %Y %H:%M:%S')) proj_obj.s_python_version(sys.version) proj_obj.s_description('Creating logical switches from ' + os.path.basename(__file__)) api_int.get_batch(session, proj_obj, _basic_capture_kpi_l, None) if proj_obj.r_is_any_error(): switch_d['err_msgs'].append( 'Error reading logical switch information from chassis' ) brcdapi_log.log( switch_d['err_msgs'][len(switch_d['err_msgs']) - 1], True) else: ec = _configure_switch(user_id, pw, session, proj_obj, switch_d, force, echo) except BaseException as e: switch_d['err_msgs'].append( 'Programming error encountered. Exception: ' + str(e)) brcdapi_log.log(switch_d['err_msgs'][len(switch_d['err_msgs']) - 1], True) ec = brcddb_common.EXIT_STATUS_ERROR # Logout and create and print a summary report if session is not None: obj = brcdapi_rest.logout(session) if fos_auth.is_error(obj): brcdapi_log.log(fos_auth.formatted_error_msg(obj), True) ec = brcddb_common.EXIT_STATUS_API_ERROR if ip is not None: _print_summary(switch_d_list) return ec
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 """ # Get and validate the input parameters. Add all input arguments to the log ip, user_id, pw, sec, cli_file, fid, t_flag, f_flag, b_flag, s_flag, vd, log, nl = parse_args( ) if not nl: brcdapi_log.open_log(log) if vd: brcdapi_rest.verbose_debug = True content = { 'fid': fid, 'ip-addr': ip, 'id': user_id, 'pw': pw, 'sec': sec, 'force': False if f_flag is None else f_flag, 'test': False if t_flag is None else t_flag, 'bulk': False if b_flag is None else b_flag, } if s_flag: brcdapi_log.set_suppress_all() ml = list() if _DEBUG: ml.append('WARNING!!! Debug is enabled') ml.append('IP: ' + brcdapi_util.mask_ip_addr(ip, True)) ml.append('ID: ' + user_id) ml.append('CLI file: ' + cli_file) ml.append('FID: ' + str(fid)) ml.append('Test flag: ' + str(t_flag)) ml.append('Force flag: ' + str(f_flag)) ml.append('Bulk flag: ' + str(b_flag)) brcdapi_log.log(ml, True) # Read in the CLI file, condition the input strings and send it ml = list() try: file_contents = brcdapi_file.read_file(cli_file) except FileNotFoundError: ml.extend([ '', 'File ' + cli_file + ' not found. Did you remember the file extension?' ]) except PermissionError: ml.extend(['', 'You do not have permission to read ' + cli_file]) if len(ml) > 0: brcdapi_log.log(ml, True) return brcddb_common.EXIT_STATUS_INPUT_ERROR content.update(changes=brcddb_util.parse_cli(file_contents)) if t_flag: content.update(test=True) response = brcddb_zone.send_zoning(content) # General information ec = brcddb_common.EXIT_STATUS_OK total_changes = total_failures = total_io = i = 0 for obj in response: if isinstance( obj, dict ): # obj is None for blank or commented our lines in the input if obj.get('changed'): total_changes += 1 if obj.get('fail'): total_failures += 1 brcdapi_log.log(_format_fault(obj, i, file_contents), True) ec = brcddb_common.EXIT_STATUS_ERROR if obj.get('io'): total_io += 1 i += 1 ml = [ '', 'Summary:', 'Total Changes : ' + str(total_changes), 'Total Failures : ' + str(total_failures), 'Total I/O : ' + str(total_io) ] brcdapi_log.log(ml, True) return ec
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, _DEFAULT_POLL_INTERVAL, _DEFAULT_MAX_SAMPLE, _proj_obj, _session, _out_f, _switch_obj global _base_switch_obj, __version__, _uris, _uris_2 signal.signal(signal.SIGINT, _signal_handler) # Get user input ip, user_id, pw, sec, fid, pct, max_p, _out_f = _get_input() default_text = ' (default)' ml = ['WARNING!!! Debug is enabled'] if _DEBUG else list() ml.append(os.path.basename(__file__) + ' version: ' + __version__) ml.append('IP Address: ' + brcdapi_util.mask_ip_addr(ip)) ml.append('User ID: ' + user_id) ml.append('FID: ' + str(fid)) if max_p is None: max_p = _DEFAULT_MAX_SAMPLE ml.append('Samples: ' + str(max_p) + default_text) else: ml.append('Samples: ' + str(max_p)) if pct is None: pct = _DEFAULT_POLL_INTERVAL ml.append('Poll Interval: ' + str(pct) + default_text) else: ml.append('Poll Interval: ' + str(pct) + ' (defaulting to ' + str(_MIN_POLL) + ')' if pct < _MIN_POLL else '') ml.append('Output File: ' + _out_f) brcdapi_log.log(ml, True) # Create project _proj_obj = brcddb_project.new( 'Port_Stats', datetime.datetime.now().strftime('%d %b %Y %H:%M:%S')) _proj_obj.s_python_version(sys.version) _proj_obj.s_description('Port statistics') # Login _session = brcddb_int.login(user_id, pw, ip, sec, _proj_obj) if fos_auth.is_error(_session): brcdapi_log.log(fos_auth.formatted_error_msg(_session), True) return brcddb_common.EXIT_STATUS_ERROR try: # I always put all code after login in a try/except in case of a code bug or network error, I still logout # Capture the initial switch and port information along with the first set of statistics. brcdapi_log.log('Capturing initial data', True) brcddb_int.get_batch(_session, _proj_obj, _uris, fid) # Captured data is put in _proj_obj chassis_obj = _proj_obj.r_chassis_obj(_session.get('chassis_wwn')) if chassis_obj.r_is_vf_enabled(): if fid is None: fid = 128 _base_switch_obj = chassis_obj.r_switch_obj_for_fid(fid) else: _base_switch_obj = chassis_obj.r_switch_objects()[0] if _base_switch_obj is None: brcdapi_log.log('Switch for FID ' + str(fid) + ' not found. ', True) return _wrap_up(brcddb_common.EXIT_STATUS_ERROR) base_switch_wwn = _base_switch_obj.r_obj_key() if _base_switch_obj.r_fabric_key() is None: _base_switch_obj.s_fabric_key( base_switch_wwn ) # Fake out a fabric principal if we don't have one _proj_obj.s_add_fabric(base_switch_wwn) brcddb_int.get_batch(_session, _proj_obj, _uris_2, fid) # Captured data is put in _proj_obj time.sleep( 5 ) # Somewhat arbitrary time. Don't want a throttling delay if the poll interval is very short # Get the first sample stats_buf = 'brocade-interface/fibrechannel-statistics' last_time = time.time() last_stats = brcddb_int.get_rest(_session, stats_buf, _base_switch_obj, fid) for p in last_stats.get('fibrechannel-statistics'): _base_switch_obj.r_port_obj(p.get('name')).s_new_key( 'fibrechannel-statistics', p) # Now start collecting the port and interface statistics for i in range(0, max_p): x = pct - (time.time() - last_time) time.sleep(_MIN_POLL if x < _MIN_POLL else x) switch_obj = _proj_obj.s_add_switch(base_switch_wwn + '-' + str(i)) last_time = time.time() obj = brcddb_int.get_rest(_session, 'brocade-interface/fibrechannel', switch_obj, fid) if not fos_auth.is_error(obj): for p in obj.get('fibrechannel'): switch_obj.s_add_port(p.get('name')).s_new_key( 'fibrechannel', p) obj = brcddb_int.get_rest(_session, stats_buf, switch_obj, fid) if fos_auth.is_error( obj ): # We typically get here when the login times out or network fails. brcdapi_log.log( 'Error encountered. Data collection limited to ' + str(i) + ' samples.', True) _wrap_up(brcddb_common.EXIT_STATUS_ERROR) return brcddb_common.EXIT_STATUS_ERROR obj = brcddb_int.get_rest(_session, stats_buf, switch_obj, fid) if fos_auth.is_error( obj ): # We typically get here when the login times out or network fails. brcdapi_log.log( 'Error encountered. Data collection limited to ' + str(i) + ' samples.', True) _wrap_up(brcddb_common.EXIT_STATUS_ERROR) return brcddb_common.EXIT_STATUS_ERROR for p in _stats_diff(last_stats, obj).get('fibrechannel-statistics'): switch_obj.s_add_port(p.get('name')).s_new_key( 'fibrechannel-statistics', p) _switch_obj.append(switch_obj) last_stats = obj return _wrap_up(brcddb_common.EXIT_STATUS_OK) except BaseException as e: brcdapi_log.log([ 'Error capturing statistics. ' + _EXCEPTION_MSG, 'Exception: ' + str(e) ], True) return _wrap_up(brcddb_common.EXIT_STATUS_ERROR)
def _get_project(sl, pl, addl_parms): """Reads or captures project data :param sl: List of switches to poll via the API :type sl: list :param pl: List of project files to combine :type pl: list :param addl_parms: Additional parameters (debug and logging) to be passed to capture.py. :type addl_parms: list :return rl: List of error messages :rtype: list :return proj_obj: Project object. None if there was an error obtaining the project object :rtype proj_obj: brcddb.classes.project.ProjObj, None """ global _ZONE_KPI_FILE rl = list() # Error messages # Create project proj_obj = brcddb_project.new( 'zone_merge', datetime.datetime.now().strftime('%d %b %Y %H:%M:%S')) proj_obj.s_python_version(sys.version) proj_obj.s_description('Zone merge') # Get a unique folder name for multi_capture.py and combine.py folder_l = [f for f in os.listdir('.') if not isfile(f)] base_folder = '_zone_merge_work_folder_' i = 0 work_folder = base_folder + str(i) while work_folder in folder_l: i += 1 work_folder = base_folder + str(i) os.mkdir(work_folder) # Add the KPI file for the captures zone_kpi_file = work_folder + '/' + _ZONE_KPI_FILE f = open(zone_kpi_file, 'w') f.write('\n'.join(_kpis_for_capture) + '\n') f.close() # Start all the data captures for the switches to be polled so that multiple switches can be captured in parallel if len(sl) > 0: brcdapi_log.log('Collecting zoning data from switches', True) captured_d = dict() pid_l = list() for sub_d in sl: ip_addr = sub_d['ip'] file_name = work_folder + '/switch_' + ip_addr.split( '.').pop() + '_' + str(len(pid_l)) sub_d.update(file=file_name) file_name = brcdapi_file.full_file_name(file_name, '.json') d = captured_d.get(ip_addr) if d is None: sub_d_l = list() captured_d.update({ip_addr: dict(sub_d_l=sub_d_l, file=file_name)}) params = [ 'python.exe', 'capture.py', '-ip', ip_addr, '-id', sub_d['id'], '-pw', sub_d['pw'], '-s', 'none' if sub_d['sec'] is None else sub_d['sec'], '-f', file_name, '-c', zone_kpi_file ] + addl_parms pid_l.append( dict(p=subprocess.Popen(params), file_name=file_name, ip=ip_addr)) sub_d_l.append(sub_d) # Add the data read from this chassis to the project object for pid_d in pid_l: # Wait for all captures to complete before continuing pid_d.update(s=pid_d['p'].wait()) brcdapi_log.log( 'Completed capture for ' + pid_d['file_name'] + '. Ending status: ' + str(pid_d['s']), True) for pid_d in pid_l: obj = brcdapi_file.read_dump(pid_d['file_name']) if obj is None: rl.append('Capture for ' + file_name + '. failed.') else: brcddb_copy.plain_copy_to_brcddb(obj, proj_obj) captured_d[pid_d['ip']].update(fab_keys=obj['_fabric_objs'].keys()) if len(rl) > 0: return rl, proj_obj # Figure out the fabric WWN for all the FIDs for the polled switches for d in captured_d.values(): fab_obj_l = [proj_obj.r_fabric_obj(k) for k in d['fab_keys']] for fab_obj in fab_obj_l: if fab_obj.r_get( 'zone_merge' ) is None: # I can't think of a reason why it wouldn't be None fab_obj.s_new_key('zone_merge', dict(file=d['file'])) for sub_d in d['sub_d_l']: found = False fid = sub_d['fid'] if isinstance( fid, int ): # If the user is just running a scan, there won't be a fid for fab_obj in fab_obj_l: if fid in brcddb_fabric.fab_fids(fab_obj): s_buf = 'none' if sub_d['sec'] is None else sub_d['sec'] zm_d = fab_obj.r_get('zone_merge') zm_d.update(fab_wwn=fab_obj.r_obj_key(), update=sub_d['update'], cfg=sub_d['cfg'], fid=sub_d['fid'], ip=sub_d['ip'], id=sub_d['id'], pw=sub_d['pw'], sec=s_buf) fab_obj.s_new_key('zone_merge', zm_d) found = True break if not found: rl.append('Could not find FID ' + str(fid) + ' in ' + brcdapi_util.mask_ip_addr(sub_d['ip'])) # Add in all the read in project files if len(pl) > 0: brcdapi_log.log('Reading project files', True) for sub_d in pl: file_name = brcdapi_file.full_file_name(sub_d['project_file'], '.json') obj = brcdapi_file.read_dump(file_name) brcddb_copy.plain_copy_to_brcddb(obj, proj_obj) for fab_obj in [ proj_obj.r_fabric_obj(k) for k in obj['_fabric_objs'].keys() ]: if fab_obj.r_get( 'zone_merge' ) is None: # It should be None. This is just future proofing. fab_obj.s_new_key('zone_merge', dict(file=file_name)) fab_obj = proj_obj.r_fabric_obj(sub_d.get('fab_wwn')) if fab_obj is None: rl.append('Could not find fabric WWN ' + str(sub_d.get('fab_wwn')) + ' in ' + file_name) else: fab_obj.r_get('zone_merge').update(fab_wwn=fab_obj.r_obj_key(), update=False, cfg=sub_d['cfg']) return rl, proj_obj