3737
3838import nodescraper
3939from nodescraper .cli .compare_runs import run_compare_runs
40- from nodescraper .cli .constants import DEFAULT_CONFIG , META_VAR_MAP
40+ from nodescraper .cli .constants import (
41+ DEFAULT_CONFIG ,
42+ KEYBOARD_INTERRUPT_EXIT_CODE ,
43+ META_VAR_MAP ,
44+ )
4145from nodescraper .cli .dynamicparserbuilder import DynamicParserBuilder
4246from nodescraper .cli .helper import (
4347 dump_results_to_csv ,
@@ -459,6 +463,14 @@ def setup_logger(
459463 return logger
460464
461465
466+ def _handle_keyboard_interrupt (logger : Optional [logging .Logger ] = None ) -> None :
467+ if logger is not None :
468+ logger .info ("Received Ctrl+C. Shutting down..." )
469+ else :
470+ sys .stderr .write ("Interrupted.\n " )
471+ sys .exit (KEYBOARD_INTERRUPT_EXIT_CODE )
472+
473+
462474def main (
463475 arg_input : Optional [list [str ]] = None ,
464476 * ,
@@ -474,169 +486,175 @@ def main(
474486 plugin_run_result_hooks: Optional callbacks invoked with each plugin's :class:`PluginResult`
475487 after ``run()`` completes (used by embedded hosts such as error-scraper).
476488 """
477- if arg_input is None :
478- arg_input = sys .argv [1 :]
479-
480- plugin_reg = PluginRegistry ()
481- config_reg = _default_config_registry (plugin_reg )
482- parser , plugin_subparser_map = build_parser (plugin_reg , config_reg )
483-
489+ logger : Optional [logging .Logger ] = None
484490 try :
485- top_level_args , plugin_arg_map , invalid_plugins = process_args (
486- arg_input , list (plugin_subparser_map .keys ())
487- )
491+ if arg_input is None :
492+ arg_input = sys .argv [1 :]
488493
489- parsed_args = parser .parse_args (top_level_args )
490- apply_host_cli_args_to_parsed_args (parsed_args , host_cli_args )
491- merge_plugin_connection_config_from_host_ns (parsed_args , host_cli_args )
492- system_info = get_system_info (parsed_args )
493- sname = system_info .name .lower ().replace ("-" , "_" ).replace ("." , "_" )
494- timestamp = datetime .datetime .now ().strftime ("%Y_%m_%d-%I_%M_%S_%p" )
495-
496- if parsed_args .log_path :
497- log_path = os .path .join (
498- parsed_args .log_path ,
499- f"scraper_logs_{ sname } _{ timestamp } " ,
500- )
501- os .makedirs (log_path )
502- else :
503- log_path = None
494+ plugin_reg = PluginRegistry ()
495+ config_reg = _default_config_registry (plugin_reg )
496+ parser , plugin_subparser_map = build_parser (plugin_reg , config_reg )
504497
505- if parsed_args .no_console_log and not log_path :
506- base_dir = parsed_args .log_path if parsed_args .log_path else "."
507- log_path = os .path .join (base_dir , f"scraper_logs_{ sname } _{ timestamp } " )
508- os .makedirs (log_path , exist_ok = True )
509-
510- logger = setup_logger (
511- parsed_args .log_level ,
512- log_path ,
513- console = not parsed_args .no_console_log ,
514- )
515- if log_path :
516- logger .info ("Log path: %s" , log_path )
517-
518- # Log warning if invalid plugin names were provided
519- if invalid_plugins :
520- logger .warning (
521- "Invalid plugin name(s) ignored: %s. Use 'describe plugin' to list available plugins." ,
522- ", " .join (invalid_plugins ),
498+ try :
499+ top_level_args , plugin_arg_map , invalid_plugins = process_args (
500+ arg_input , list (plugin_subparser_map .keys ())
523501 )
524502
525- if parsed_args .subcmd == "summary" :
526- generate_summary (
527- parsed_args .search_path ,
528- parsed_args .output_path ,
529- logger ,
530- artifact_dir = log_path ,
531- )
532- sys .exit (0 )
503+ parsed_args = parser .parse_args (top_level_args )
504+ apply_host_cli_args_to_parsed_args (parsed_args , host_cli_args )
505+ merge_plugin_connection_config_from_host_ns (parsed_args , host_cli_args )
506+ system_info = get_system_info (parsed_args )
507+ sname = system_info .name .lower ().replace ("-" , "_" ).replace ("." , "_" )
508+ timestamp = datetime .datetime .now ().strftime ("%Y_%m_%d-%I_%M_%S_%p" )
509+
510+ if parsed_args .log_path :
511+ log_path = os .path .join (
512+ parsed_args .log_path ,
513+ f"scraper_logs_{ sname } _{ timestamp } " ,
514+ )
515+ os .makedirs (log_path )
516+ else :
517+ log_path = None
533518
534- if parsed_args .subcmd == "describe" :
535- parse_describe (parsed_args , plugin_reg , config_reg , logger )
536-
537- if parsed_args .subcmd == "compare-runs" :
538- run_compare_runs (
539- parsed_args .path1 ,
540- parsed_args .path2 ,
541- plugin_reg ,
542- logger ,
543- skip_plugins = getattr (parsed_args , "skip_plugins" , None ) or [],
544- include_plugins = getattr (parsed_args , "include_plugins" , None ),
545- truncate_message = not getattr (parsed_args , "dont_truncate" , False ),
546- artifact_dir = log_path ,
547- )
548- sys .exit (0 )
519+ if parsed_args .no_console_log and not log_path :
520+ base_dir = parsed_args .log_path if parsed_args .log_path else "."
521+ log_path = os .path .join (base_dir , f"scraper_logs_{ sname } _{ timestamp } " )
522+ os .makedirs (log_path , exist_ok = True )
549523
550- if parsed_args .subcmd == "show-redfish-oem-allowable" :
551- if not parsed_args .connection_config :
552- parser .error ("show-redfish-oem-allowable requires --connection-config" )
553- raw = parsed_args .connection_config .get ("RedfishConnectionManager" )
554- if not raw :
555- logger .error ("Connection config must contain RedfishConnectionManager" )
556- sys .exit (1 )
557- params = RedfishConnectionParams .model_validate (raw )
558- password = params .password .get_secret_value () if params .password else None
559- base_url = f"{ 'https' if params .use_https else 'http' } ://{ params .host } " + (
560- f":{ params .port } " if params .port else ""
561- )
562- conn = RedfishConnection (
563- base_url = base_url ,
564- username = params .username ,
565- password = password ,
566- timeout = params .timeout_seconds ,
567- use_session_auth = params .use_session_auth ,
568- verify_ssl = params .verify_ssl ,
569- api_root = params .api_root ,
524+ logger = setup_logger (
525+ parsed_args .log_level ,
526+ log_path ,
527+ console = not parsed_args .no_console_log ,
570528 )
571- try :
572- conn ._ensure_session ()
573- allowable = get_oem_diagnostic_allowable_values (conn , parsed_args .log_service_path )
574- if allowable is None :
575- logger .warning (
576- "Could not read OEMDiagnosticDataType@Redfish.AllowableValues from LogService"
577- )
578- sys .exit (1 )
579- logger .info ("%s" , json .dumps (allowable , indent = 2 ))
580- finally :
581- conn .close ()
582- sys .exit (0 )
529+ if log_path :
530+ logger .info ("Log path: %s" , log_path )
531+
532+ # Log warning if invalid plugin names were provided
533+ if invalid_plugins :
534+ logger .warning (
535+ "Invalid plugin name(s) ignored: %s. Use 'describe plugin' to list available plugins." ,
536+ ", " .join (invalid_plugins ),
537+ )
538+
539+ if parsed_args .subcmd == "summary" :
540+ generate_summary (
541+ parsed_args .search_path ,
542+ parsed_args .output_path ,
543+ logger ,
544+ artifact_dir = log_path ,
545+ )
546+ sys .exit (0 )
583547
584- if parsed_args .subcmd == "gen-plugin-config" :
548+ if parsed_args .subcmd == "describe" :
549+ parse_describe (parsed_args , plugin_reg , config_reg , logger )
550+
551+ if parsed_args .subcmd == "compare-runs" :
552+ run_compare_runs (
553+ parsed_args .path1 ,
554+ parsed_args .path2 ,
555+ plugin_reg ,
556+ logger ,
557+ skip_plugins = getattr (parsed_args , "skip_plugins" , None ) or [],
558+ include_plugins = getattr (parsed_args , "include_plugins" , None ),
559+ truncate_message = not getattr (parsed_args , "dont_truncate" , False ),
560+ artifact_dir = log_path ,
561+ )
562+ sys .exit (0 )
585563
586- if parsed_args .reference_config_from_logs :
587- ref_config = generate_reference_config_from_logs (
588- parsed_args .reference_config_from_logs , plugin_reg , logger
564+ if parsed_args .subcmd == "show-redfish-oem-allowable" :
565+ if not parsed_args .connection_config :
566+ parser .error ("show-redfish-oem-allowable requires --connection-config" )
567+ raw = parsed_args .connection_config .get ("RedfishConnectionManager" )
568+ if not raw :
569+ logger .error ("Connection config must contain RedfishConnectionManager" )
570+ sys .exit (1 )
571+ params = RedfishConnectionParams .model_validate (raw )
572+ password = params .password .get_secret_value () if params .password else None
573+ base_url = f"{ 'https' if params .use_https else 'http' } ://{ params .host } " + (
574+ f":{ params .port } " if params .port else ""
575+ )
576+ conn = RedfishConnection (
577+ base_url = base_url ,
578+ username = params .username ,
579+ password = password ,
580+ timeout = params .timeout_seconds ,
581+ use_session_auth = params .use_session_auth ,
582+ verify_ssl = params .verify_ssl ,
583+ api_root = params .api_root ,
589584 )
590- out_dir = log_path if log_path else parsed_args .output_path
591- path = os .path .join (out_dir , "reference_config.json" )
592585 try :
593- with open (path , "w" ) as f :
594- json .dump (
595- ref_config .model_dump (mode = "json" , exclude_none = True ),
596- f ,
597- indent = 2 ,
586+ conn ._ensure_session ()
587+ allowable = get_oem_diagnostic_allowable_values (
588+ conn , parsed_args .log_service_path
589+ )
590+ if allowable is None :
591+ logger .warning (
592+ "Could not read OEMDiagnosticDataType@Redfish.AllowableValues from LogService"
598593 )
599- logger .info ("Reference config written to: %s" , path )
600- except Exception as exp :
601- logger .error (exp )
594+ sys .exit (1 )
595+ logger .info ("%s" , json .dumps (allowable , indent = 2 ))
596+ finally :
597+ conn .close ()
602598 sys .exit (0 )
603599
604- parse_gen_plugin_config (
605- parsed_args , plugin_reg , config_reg , logger , artifact_dir = log_path
606- )
600+ if parsed_args .subcmd == "gen-plugin-config" :
607601
608- parsed_plugin_args = {}
609- for plugin , plugin_args in plugin_arg_map .items ():
610- try :
611- parsed_plugin_args [plugin ] = plugin_subparser_map [plugin ][0 ].parse_args (plugin_args )
612- except Exception as e :
613- logger .error ("%s exception parsing args for plugin: %s" , str (e ), plugin )
602+ if parsed_args .reference_config_from_logs :
603+ ref_config = generate_reference_config_from_logs (
604+ parsed_args .reference_config_from_logs , plugin_reg , logger
605+ )
606+ out_dir = log_path if log_path else parsed_args .output_path
607+ path = os .path .join (out_dir , "reference_config.json" )
608+ try :
609+ with open (path , "w" ) as f :
610+ json .dump (
611+ ref_config .model_dump (mode = "json" , exclude_none = True ),
612+ f ,
613+ indent = 2 ,
614+ )
615+ logger .info ("Reference config written to: %s" , path )
616+ except Exception as exp :
617+ logger .error (exp )
618+ sys .exit (0 )
619+
620+ parse_gen_plugin_config (
621+ parsed_args , plugin_reg , config_reg , logger , artifact_dir = log_path
622+ )
614623
615- if not parsed_plugin_args and not parsed_args .plugin_configs :
616- logger .info (
617- "No plugins config args specified, running default config: %s" , DEFAULT_CONFIG
624+ parsed_plugin_args = {}
625+ for plugin , plugin_args in plugin_arg_map .items ():
626+ try :
627+ parsed_plugin_args [plugin ] = plugin_subparser_map [plugin ][0 ].parse_args (
628+ plugin_args
629+ )
630+ except Exception as e :
631+ logger .error ("%s exception parsing args for plugin: %s" , str (e ), plugin )
632+
633+ if not parsed_plugin_args and not parsed_args .plugin_configs :
634+ logger .info (
635+ "No plugins config args specified, running default config: %s" ,
636+ DEFAULT_CONFIG ,
637+ )
638+ plugin_configs = [DEFAULT_CONFIG ]
639+ else :
640+ plugin_configs = parsed_args .plugin_configs or []
641+
642+ plugin_config_inst_list = get_plugin_configs (
643+ plugin_config_input = plugin_configs ,
644+ system_interaction_level = parsed_args .sys_interaction_level ,
645+ built_in_configs = config_reg .configs ,
646+ parsed_plugin_args = parsed_plugin_args ,
647+ plugin_subparser_map = plugin_subparser_map ,
618648 )
619- plugin_configs = [DEFAULT_CONFIG ]
620- else :
621- plugin_configs = parsed_args .plugin_configs or []
622-
623- plugin_config_inst_list = get_plugin_configs (
624- plugin_config_input = plugin_configs ,
625- system_interaction_level = parsed_args .sys_interaction_level ,
626- built_in_configs = config_reg .configs ,
627- parsed_plugin_args = parsed_plugin_args ,
628- plugin_subparser_map = plugin_subparser_map ,
629- )
630649
631- if parsed_args .skip_sudo :
632- plugin_config_inst_list [- 1 ].global_args .setdefault ("collection_args" , {})[
633- "skip_sudo"
634- ] = True
650+ if parsed_args .skip_sudo :
651+ plugin_config_inst_list [- 1 ].global_args .setdefault ("collection_args" , {})[
652+ "skip_sudo"
653+ ] = True
635654
636- except Exception as e :
637- parser .error (str (e ))
655+ except Exception as e :
656+ parser .error (str (e ))
638657
639- try :
640658 results = run_plugin_queue_with_invocation (
641659 plugin_reg = plugin_reg ,
642660 parsed_args = parsed_args ,
@@ -683,8 +701,7 @@ def main(
683701 else :
684702 sys .exit (0 )
685703 except KeyboardInterrupt :
686- logger .info ("Received Ctrl+C. Shutting down..." )
687- sys .exit (130 )
704+ _handle_keyboard_interrupt (logger )
688705
689706
690707if __name__ == "__main__" :
0 commit comments