def handle_set_thermal_ambient(kwargs): """Configure thermal properties for room temperature""" if kwargs["event"] and kwargs["pause_at"] and kwargs["rate"]: ISystemEnvironment.set_ambient_props(kwargs) elif kwargs["event"] or kwargs["pause_at"] or kwargs["rate"]: raise argparse.ArgumentTypeError( "Event, pause-at and rate must be supplied") else: StateClient.set_ambient(kwargs["degrees"])
def handle_voltage_set(args): """Action callback for handling voltage set command""" if args["value"] is not None: StateClient.set_voltage(args["value"]) del args["value"] # set voltage fluctuation properties if any are provided if [arg_value for _, arg_value in args.items() if arg_value is not None]: ISystemEnvironment.set_voltage_props(args)
def cv_command(cv_group): """Endpoints for CacheVault properties""" cv_group = cv_group.add_subparsers() # CLI PD setter set_cv_action = cv_group.add_parser("set", help="Configure CacheVault", parents=[get_ctrl_storage_args()]) set_cv_action.add_argument( "-r", "--replacement-required", help="Correctable RAM errors on disk data", choices=["Yes", "No"], required=True, ) set_cv_action.add_argument( "-w", "--write-through-fail", help= "Virtual drive endpoint will fail to report its cache mode as WT (WriteThrough)", action="store_false", ) set_cv_action.set_defaults(func=lambda args: process_cmd_result( StateClient(args["asset_key"]).set_cv_replacement( args["controller"], args)))
def pd_command(pd_group): """Endpoints for setting storage props (pd, vd, controller etc.)""" pd_subp = pd_group.add_subparsers() # group a few args into a common parent element server_controller_parent = get_ctrl_storage_args() # CLI PD setter set_pd_action = pd_subp.add_parser( "set", help="Configure a physical drive (error count, state etc.)", parents=[server_controller_parent], ) set_pd_action.add_argument("-d", "--drive-id", help="Physical Drive id (DID)", type=int, required=True) set_pd_action.add_argument( "-m", "--media-error-count", help="Update media error count for the drive", type=int, ) set_pd_action.add_argument( "-o", "--other-error-count", help="Update other error count for the drive", type=int, ) set_pd_action.add_argument( "-p", "--predictive-error-count", help="Update error prediction value for the drive", type=int, ) set_pd_action.add_argument( "-r", "--rebuild-time", help= "Time (in seconds) required to complete rebuild process for a drive", type=int, ) set_pd_action.add_argument( "-s", "--state", help="Update state if the physical drive", choices=["Onln", "Offln"], ) set_pd_action.set_defaults(func=lambda args: process_cmd_result( StateClient(args["asset_key"]).set_physical_drive_prop( args["controller"], args["drive_id"], args)))
def manage_state(asset_key, mng_action): """Perform action for a node/asset with a certain key Args: asset_key (int): supplied asset identifier mng_action (func): callable object (lambda/function etc) that identifies action """ state_manager = StateClient(asset_key) mng_action(state_manager)
def dry_run_actions(args): """Do a dry run of action replay without changing of affecting assets' states""" action_slc = get_action_slice(args["start"], args["end"]) action_details = StateClient.list_actions(action_slc) try: Recorder.perform_dry_run(action_details, action_slc) except KeyboardInterrupt: print("Dry-run was interrupted by the user", file=sys.stderr)
def controller_command(ctrl_group): """Endpoints for setting storage props (pd, vd, controller etc.)""" ctrl_subp = ctrl_group.add_subparsers() server_controller_parent = get_ctrl_storage_args() # CLI controller setter set_ctrl_action = ctrl_subp.add_parser( "set", help="Configure a specific RAID controller", parents=[server_controller_parent], ) set_ctrl_action.add_argument( "-e", "--memory-correctable-errors", help="Correctable RAM errors on disk data", type=int, required=False, dest="mem_c_errors", ) set_ctrl_action.add_argument( "-u", "--memory-uncorrectable-errors", help="Uncorrectable RAM errors on disk data", type=int, required=False, dest="mem_uc_errors", ) set_ctrl_action.add_argument( "-a", "--alarm-state", help="Controller alarm state", choices=["missing", "off", "on"], required=False, dest="alarm", ) set_ctrl_action.set_defaults(func=lambda args: process_cmd_result( StateClient(args["asset_key"]).set_controller_prop( args["controller"], args)))
def get_action_slice(start, end): """Parse start & end range specifiers Args: start: start index or starting datestring or time string in a format "%H:%M:%S" or "%Y-%m-%d %H:%M:%S" end: end index or end date/time in a format "%H:%M:%S" or "%Y-%m-%d %H:%M:%S" Returns: slice: range of actions """ try: return slice(int(start), int(end)) except (ValueError, TypeError): # attemp to parse dates if one/both of the range options are non digits all_actions = StateClient.list_actions(slice(None, None)) start = get_index_from_range_opt(start, all_actions) end = get_index_from_range_opt(end, all_actions, start_opt=False) return slice(start, end)
def power_command(power_group): """CLI endpoints for managing assets' power states & wallpower""" power_subp = power_group.add_subparsers() # Manage power of individual assets power_up_action = power_subp.add_parser( "up", help="Power up a particular component/asset" ) power_up_action.add_argument("-k", "--asset-key", type=int, required=True) power_down_action = power_subp.add_parser( "down", help="Power down a particular component/asset" ) power_down_action.add_argument("-k", "--asset-key", type=int, required=True) power_down_action.add_argument( "--hard", help="Enable abrupt poweroff instead of shutdown", dest="hard", action="store_true", ) # Wallpower management power_outage_action = power_subp.add_parser( "outage", help="Simulate complete power loss" ) power_restore_action = power_subp.add_parser( "restore", help="Restore mains power after outage" ) # Voltage system-wide voltage_action_group = power_subp.add_parser( "voltage", help="Manage systems voltage behavior" ) voltage_subp = voltage_action_group.add_subparsers() get_voltage_action = voltage_subp.add_parser( "get", help="Query current voltage configurations" ) get_voltage_action.add_argument( "--value-only", help="Return voltage value only (omit details of voltage behaviour)", action="store_true", ) set_voltage_action = voltage_subp.add_parser( "set", help="Update voltage value/voltage settings" ) set_voltage_action.add_argument( "--value", type=float, help="Update voltage value (in Volts)" ) set_voltage_action.add_argument( "--mu", type=float, help="Mean for gaussian random method for voltage fluctuations", ) set_voltage_action.add_argument( "--sigma", type=float, help="Standard deviation for gaussian random method for voltage fluctuations", ) set_voltage_action.add_argument( "--min", type=float, help="Min volt value for uniform random method for voltage fluctuations", ) set_voltage_action.add_argument( "--max", type=float, help="Max volt value for uniform random method for voltage fluctuations", ) set_voltage_action.add_argument( "--method", choices=ISystemEnvironment.voltage_random_methods(), help="Max volt value for uniform random method for voltage fluctuations", ) set_voltage_action.add_argument( "--enable-fluctuation", dest="enabled", action="store_true" ) set_voltage_action.add_argument( "--disable-fluctuation", dest="enabled", action="store_false" ) # CLI action callbacks power_outage_action.set_defaults(func=lambda _: StateClient.power_outage()) power_restore_action.set_defaults(func=lambda _: StateClient.power_restore()) power_up_action.set_defaults( func=lambda args: manage_state(args["asset_key"], lambda a: a.power_up()) ) power_down_action.set_defaults( hard=False, # abrupt shutdown if False by default func=lambda args: manage_state( args["asset_key"], lambda a: a.power_off() if args["hard"] else a.shut_down(), ), ) set_voltage_action.set_defaults(func=handle_voltage_set) get_voltage_action.set_defaults(func=handle_voltage_get)
def actions_command(actions_group): """Action command can be used to manage/replay recorded actions performed by SimEngine users""" play_subp = actions_group.add_subparsers() # replay commands replay_action = play_subp.add_parser( "replay", help="Replay actions, will replay all history if range is not provided", parents=[range_args()], ) replay_action.add_argument("-l", "--list", action="store_true", help="List re-played actions") # clear action history clear_action = play_subp.add_parser("clear", help="Purge action history", parents=[range_args()]) clear_action.add_argument("-l", "--list", action="store_true", help="List deleted actions") # misc disable_action = play_subp.add_parser( "disable", help="Disable recorder (recorder will ignore incoming commands)") enable_action = play_subp.add_parser( "enable", help="Enable recorder registering incoming actions") status_action = play_subp.add_parser( "status", help="Returns recorder status indicating if recorder is enabled \ and if it is in-process of replaying", ) list_action = play_subp.add_parser("list", help="List action history", parents=[range_args()]) dry_run_action = play_subp.add_parser( "dry-run", help="Perform a dry run of actions replay", parents=[range_args()]) save_action = play_subp.add_parser("save", help="Save action history to a file", parents=[range_args()]) save_action.add_argument("-l", "--list", action="store_true", help="Explicitly list saved actions") save_action.add_argument("-f", "--filename", type=str, required=True, help="Target file name") load_action = play_subp.add_parser( "load", help= "Load action history from a file (will override the existing actions)", parents=[range_args()], ) load_action.add_argument("-f", "--filename", type=str, required=True, help="Will load from this file") rand_action = play_subp.add_parser( "random", help="Perform random actions associated with assets") rand_action.add_argument("-c", "--count", type=int, help="Number of actions to be performed", default=1) rand_action.add_argument( "-k", "--asset-keys", nargs="+", type=int, help="Include only these assets when picking a random component,\ defaults to all if not provided", ) rand_action.add_argument( "-s", "--seconds", type=int, help="Perform actions for 'n' seconds (alternative to 'count')", ) rand_action.add_argument( "-n", "--nap-time", type=float, help= "Pause between each random action or max nap time if --min-nap is present", ) rand_action.add_argument( "-m", "--min-nap", type=float, help="Minimum sleep time, pauses between actions will be set to random\ if this value is provided", ) # cli actions/callbacks replay_action.set_defaults(func=lambda args: [ print_action_list( StateClient.list_actions( get_action_slice(args["start"], args["end"]))) if args["list"] else None, StateClient.replay_actions(get_action_slice(args["start"], args["end"]) ), ]) clear_action.set_defaults(func=lambda args: [ print_action_list( StateClient.list_actions( get_action_slice(args["start"], args["end"]))) if args["list"] else None, StateClient.clear_actions(get_action_slice(args["start"], args["end"]) ), ]) list_action.set_defaults(func=lambda args: print_action_list( StateClient.list_actions(get_action_slice(args["start"], args["end"]))) ) disable_action.set_defaults( func=lambda _: StateClient.set_recorder_status(enabled=False)) enable_action.set_defaults( func=lambda _: StateClient.set_recorder_status(enabled=True)) status_action.set_defaults( func=lambda _: print("Enabled: {enabled}\nReplaying: {replaying}". format(**StateClient.get_recorder_status()))) dry_run_action.set_defaults(func=dry_run_actions) save_action.set_defaults( func=lambda args: handle_file_command(args, StateClient.save_actions)) load_action.set_defaults( func=lambda args: handle_file_command(args, StateClient.load_actions)) rand_action.set_defaults(func=StateClient.rand_actions)
def configure_command(configure_state_group): """Update some runtime values of the system components""" conf_state_subp = configure_state_group.add_subparsers() conf_ups_action = conf_state_subp.add_parser( "ups", help="Update UPS runtime properties" ) conf_ups_action.add_argument( "-k", "--asset-key", type=int, required=True, help="Unique asset key of the UPS" ) conf_ups_action.add_argument( "-d", "--drain-speed", type=float, help="Update factor of the battery drain (1 sets to regular speed)", choices=range(1, 10001), metavar="[1-10001]", ) conf_ups_action.add_argument( "-c", "--charge-speed", type=float, help="Update factor of the battery charge (1 sets to regular speed)", choices=range(1, 10001), metavar="[1-10001]", ) conf_sensor_action = conf_state_subp.add_parser( "sensor", help="Update sensor runtime properties" ) conf_sensor_action.add_argument( "-k", "--asset-key", type=int, required=True, help="Unique asset key of the server sensor belongs to", ) conf_sensor_action.add_argument( "-s", "--sensor-name", type=str, required=True, help="Name of the sensor" ) conf_sensor_action.add_argument( "-r", "--runtime-value", required=True, help="New sensor value (will be reflected on ipmi)", ) conf_ups_action.set_defaults( func=lambda args: configure_battery(args["asset_key"], args) ) conf_sensor_action.set_defaults( func=lambda args: StateClient(args["asset_key"]).set_sensor_status( args["sensor_name"], args["runtime_value"] ) ) conf_rand_action = conf_state_subp.add_parser( "randomizer", help="Configure randomized options for actions" ) conf_rand_action.add_argument( "-k", "--asset-key", type=int, help="Unique asset key (Required if randomized \ options are associated with an asset)", ) conf_rand_action.add_argument( "-s", "--start", type=int, help="Start range value for randomized option" ) conf_rand_action.add_argument( "-e", "--end", type=int, help="End range value for randomized option" ) conf_rand_action.add_argument( "-l", "--list", action="store_true", help="List randranges for ranomizable options", ) conf_rand_arguments = [ "pd-media-error-count", "pd-other-error-count", "pd-predictive-error-count", "ctrl-memory-correctable-errors", "ctrl-memory-uncorrectable-errors", "ambient", ] conf_rand_action.add_argument( "-o", "--option", help="Option/Argument to be configured", choices=conf_rand_arguments, ) conf_rand_action.set_defaults(validate=validate_randomizer_options) conf_rand_action.set_defaults( func=lambda args: handle_configure_randomizer(args, conf_rand_arguments) )