Esempio n. 1
0
    def reload_model(self, force_snmp_init=True):
        """Re-create system topology (instantiate assets based on graph ref)"""

        RECORDER.enabled = False

        ISystemEnvironment.set_ambient(0)
        logger.info("Initializing system topology...")

        self._assets = {}

        # init state
        clear_temp()
        initialize(force_snmp_init)

        # get system topology
        assets = self._data_source.get_all_assets()

        for asset in assets:
            self._assets[asset["key"]] = Asset.get_supported_assets()[asset["type"]](
                asset
            ).register(self)

        self._power_iter_handler.start(on_iteration_launched=self._chain_power_events)
        self._thermal_iter_handler.start(
            on_iteration_launched=self._chain_thermal_events
        )

        ISystemEnvironment.set_ambient(21)
        RECORDER.enabled = True
Esempio n. 2
0
def handle_voltage_get(args):
    """Action callback for handling voltage get command"""

    if args["value_only"]:
        print(ISystemEnvironment.get_voltage())
        return

    print("Voltage: {:.3f}V".format(ISystemEnvironment.get_voltage()))

    voltage_props = ISystemEnvironment.get_voltage_props()
    if not voltage_props:
        print("Voltage properties are not configured yet!")
        return

    volt_fluct_info = []

    volt_fluct_info.append("Fluctuation Properties:")
    volt_fluct_info.append("[enabled]: " + str(voltage_props["enabled"]))
    volt_fluct_info.append("[random distribution method]: " + voltage_props["method"])

    if voltage_props["method"] == "gauss":
        distr_prop_fmt = "mean({mu}), stdev({sigma})"
    else:
        distr_prop_fmt = "min({min}), max({max})"

    volt_fluct_info.append(
        "[distribution properties]: " + distr_prop_fmt.format(**voltage_props)
    )

    print("\n -> ".join(volt_fluct_info))
Esempio n. 3
0
    def _handle_status_request(self, details):
        """Get overall system status/details including hardware assets;
        environment state & play details
        """

        assets = IStateManager.get_system_status(flatten=False)
        graph_ref = GraphReference()
        with graph_ref.get_session() as session:

            stage_layout = GraphReference.get_stage_layout(session)

            # send system topology and assets' power-interconnections
            self._write_data(
                details["client"],
                ServerToClientRequests.sys_layout,
                {"assets": assets, "stageLayout": stage_layout},
            )

        self._write_data(
            details["client"],
            ServerToClientRequests.ambient_upd,
            {"ambient": ISystemEnvironment.get_ambient(), "rising": False},
        )

        self._write_data(
            details["client"],
            ServerToClientRequests.play_list,
            {"plays": list(itertools.chain(*IStateManager.plays()))},
        )

        self._write_data(
            details["client"],
            ServerToClientRequests.mains_upd,
            {"mains": ISystemEnvironment.mains_status()},
        )
Esempio n. 4
0
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)
Esempio n. 5
0
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"])
Esempio n. 6
0
def model_command(asset_group):
    """Aggregates system modelling cli commands"""

    model_subp = asset_group.add_subparsers()

    # creational cmds
    create_command(model_subp.add_parser("create", help="Create new asset"))
    update_command(
        model_subp.add_parser("update", help="Update Asset properties"))

    ## MISC model commands
    reload_asset_action = model_subp.add_parser(
        "reload",
        help="Reload the system topology (notify daemon of model changes)")

    # detach & delete an asset by key
    delete_asset_action = model_subp.add_parser(
        "delete", help="Remove individual asset by key")
    delete_asset_action.add_argument("-k",
                                     "--asset-key",
                                     type=int,
                                     required=True)

    # drop entire system topology
    drop_system_action = model_subp.add_parser(
        "drop", help="Delete/drop all the system components")

    # link 2 assets together
    power_asset_action = model_subp.add_parser(
        "power-link", help="Create/Delete a power link between 2 assets")
    power_asset_action.add_argument(
        "-s",
        "--source-key",
        type=int,
        required=True,
        help="Key of an asset that POWERS dest. asset",
    )
    power_asset_action.add_argument(
        "-d",
        "--dest-key",
        type=int,
        required=True,
        help="Key of the asset powered by the source-key",
    )

    power_asset_action.add_argument("-r",
                                    "--remove",
                                    action="store_true",
                                    help="Delete power conneciton if exists")

    reload_asset_action.set_defaults(
        func=lambda args: ISystemEnvironment.reload_model())

    delete_asset_action.set_defaults(
        func=lambda args: sys_modeler.delete_asset(args["asset_key"]))

    power_asset_action.set_defaults(func=handle_link)

    drop_system_action.set_defaults(func=lambda args: sys_modeler.drop_model())
Esempio n. 7
0
def handle_configure_randomizer(args, conf_rand_arguments):
    """Callback for CLI command for configuring randomizer"""

    # list all the randoptions
    if args["list"]:
        amb_props = ISystemEnvironment.get_ambient_props()

        print(
            "Ambient random arguments: range from {start} to {end}".format(**amb_props)
        )

        if not args["asset_key"]:
            return

        del conf_rand_arguments[conf_rand_arguments.index("ambient")]

        server_manager = get_server_state_manager(args["asset_key"])
        print("Server:[{0.key}] random arguments:".format(server_manager))
        for rand_opt in conf_rand_arguments:

            s_prop = IBMCServerStateManager.StorageRandProps[rand_opt.replace("-", "_")]
            opt_prop = server_manager.get_storage_radnomizer_prop(s_prop)
            print(
                " -- {}: range from {} to {}".format(rand_opt, opt_prop[0], opt_prop[1])
            )
        return

    # configure randargs - validate cli options
    if not args["start"] or not args["end"] or not args["option"]:
        raise argparse.ArgumentTypeError(
            "Must provide rand option, start & end range values!"
        )

    # update ambient option
    if args["option"] == "ambient":
        ISystemEnvironment.set_ambient_props(args)
        return

    # update one of the server disk options
    server_manager = get_server_state_manager(args["asset_key"])
    server_manager.set_storage_randomizer_prop(
        IBMCServerStateManager.StorageRandProps[args["option"].replace("-", "_")],
        slice(args["start"], args["end"]),
    )
Esempio n. 8
0
def handle_get_thermal_ambient(kwargs):
    """Print some general information about ambient configurations"""

    if kwargs["value_only"]:
        print(ISystemEnvironment.get_ambient())
    else:
        print("Ambient: {}° ".format(ISystemEnvironment.get_ambient()))

        ambient_props = ISystemEnvironment.get_ambient_props()
        if not ambient_props:
            print("Ambient event properties are not configured yet!")
            return

        prop_fmt = "{degrees}°/{rate} sec, until {pauseAt}° is reached"
        print("AC settings:")
        print(" -> [online]  : decrease by " +
              prop_fmt.format(**ambient_props["up"]))
        print(" -> [offline] : increase by " +
              prop_fmt.format(**ambient_props["down"]))
Esempio n. 9
0
    def _handle_rand_act(self, details):
        """Handle perform random actions request"""

        rand_session_specs = details["payload"]
        assets = IStateManager.get_system_status(flatten=True)
        nap = None

        # filter out assets if range is provided
        if rand_session_specs["asset_keys"]:
            assets = list(
                filter(lambda x: x in rand_session_specs["asset_keys"], assets)
            )

        if not assets and not 0 in rand_session_specs["asset_keys"]:
            logger.warning("No assets selected for random actions")
            return

        state_managers = list(map(IStateManager.get_state_manager_by_key, assets))

        if (
            not rand_session_specs["asset_keys"]
            or 0 in rand_session_specs["asset_keys"]
        ):
            state_managers.append(ISystemEnvironment())

        if rand_session_specs["nap_time"]:

            def nap_calc():
                nap_time = lambda: rand_session_specs["nap_time"]
                if rand_session_specs["min_nap"]:
                    nap_time = lambda: random.randrange(
                        rand_session_specs["min_nap"], rand_session_specs["nap_time"]
                    )

                time.sleep(nap_time())

            nap = nap_calc

        rand_t = threading.Thread(
            target=Randomizer.randact,
            args=(state_managers,),
            kwargs={
                "num_iter": rand_session_specs["count"],
                "seconds": rand_session_specs["seconds"],
                "nap": nap,
            },
            name="[#] Randomizer",
        )

        rand_t.daemon = True
        rand_t.start()
Esempio n. 10
0
def get_status(**kwargs):
    """Retrieve power states of the assets
    Args:
        **kwargs: Command line options
    """

    #### one asset ####
    if kwargs["asset_key"] and kwargs["load"]:

        state_manager = IStateManager.get_state_manager_by_key(kwargs["asset_key"])

        if kwargs["value_only"]:
            print(state_manager.load)
        else:
            print(
                "{}-{} : {}".format(
                    state_manager.key, state_manager.asset_type, state_manager.load
                )
            )
        return
    elif kwargs["asset_key"] and kwargs["agent"]:
        state_manager = IStateManager.get_state_manager_by_key(kwargs["asset_key"])
        agent_info = state_manager.agent
        if agent_info:
            msg = "running" if agent_info[1] else "not running"
            if kwargs["value_only"]:
                print(int(agent_info[1]))
            else:
                print(
                    "{}-{} : pid[{}] is {}".format(
                        state_manager.key, state_manager.asset_type, agent_info[0], msg
                    )
                )
        else:
            print(
                "{}-{} is not running any agents!".format(
                    state_manager.key, state_manager.asset_type
                )
            )

        return
    elif kwargs["asset_key"]:
        state_manager = IStateManager.get_state_manager_by_key(kwargs["asset_key"])
        if kwargs["value_only"]:
            print(state_manager.status)
        else:
            print(
                "{}-{} : {}".format(
                    state_manager.key, state_manager.asset_type, state_manager.status
                )
            )
        return
    elif kwargs["mains"]:
        mains_status = ISystemEnvironment.mains_status()
        if kwargs["value_only"]:
            print(mains_status)
        else:
            print("Wallpower status:", mains_status)
        return

    ##### list states #####
    assets = IStateManager.get_system_status()

    # json format
    if kwargs["json"]:
        print(json.dumps(assets, indent=4))

    # monitor state with curses
    elif kwargs["monitor"]:
        stdscr = curses.initscr()

        curses.noecho()
        curses.cbreak()

        try:
            curses.start_color()
            curses.use_default_colors()
            for i in range(0, curses.COLORS):
                curses.init_pair(i, i, -1)
            while True:
                status_table_format(assets, stdscr)
                time.sleep(kwargs["watch_rate"])
                assets = IStateManager.get_system_status()
        except KeyboardInterrupt:
            pass
        finally:
            curses.echo()
            curses.nocbreak()
            curses.endwin()

    # human-readable table
    else:
        status_table_format(assets)
Esempio n. 11
0
def create_command(create_asset_group):
    """Model creation (cli endpoints to initialize system topology)"""

    # parent will contain args shared by all the asset types
    # (such as key, [x,y] positions, name etc.)
    create_asset_parent = argparse.ArgumentParser(add_help=False)
    create_asset_parent.add_argument(
        "-k",
        "--asset-key",
        type=int,
        required=True,
        help="Unique asset key (must be <= 9999)",
    )
    create_asset_parent.add_argument("--on-delay",
                                     type=int,
                                     help="Power on delay in ms",
                                     default=0)

    create_asset_parent.add_argument("--off-delay",
                                     type=int,
                                     help="Power on delay in ms",
                                     default=0)

    create_asset_parent.add_argument(
        "-x", type=int, help="x - asset position on the dashboard", default=0)
    create_asset_parent.add_argument(
        "-y", type=int, help="y - asset position on the dashboard", default=0)

    create_asset_parent.add_argument(
        "--power-on-ac",
        dest="power_on_ac",
        action="store_true",
        help="Power up on AC restored",
    )
    create_asset_parent.add_argument(
        "--no-power-on-ac",
        dest="power_on_ac",
        action="store_false",
        help="Don't power up when AC is restored",
    )

    create_asset_parent.add_argument("-n",
                                     "--name",
                                     help="Name displayed on the UI")
    create_asset_parent.set_defaults(new_asset=True, power_on_ac=True)

    create_volt_parent = argparse.ArgumentParser(add_help=False)
    create_volt_parent.add_argument(
        "--min-voltage",
        type=float,
        help="Voltage value below/at which asset stops functioning",
        default=90.0,
    )

    # snmp group parent will contain snmp-specific args
    create_snmp_parent = argparse.ArgumentParser(add_help=False)
    create_snmp_parent.add_argument("--host",
                                    type=str,
                                    default="localhost",
                                    help="SNMP interface host")
    create_snmp_parent.add_argument("--port",
                                    type=int,
                                    required=True,
                                    help="SNMP interface port")
    create_snmp_parent.add_argument(
        "--snmp-preset", type=str, help="Vendor-specific asset configurations")

    create_snmp_parent.add_argument(
        "--serial-number",
        type=str,
        help="Serial number of a simulated SNMP device")

    create_snmp_parent.add_argument(
        "--mac-address",
        type=str,
        help="MAC address of a simulated SNMP device")

    create_snmp_parent.add_argument(
        "--interface",
        type=str,
        help="Network interface attached to SNMP device")

    create_snmp_parent.add_argument("--mask",
                                    type=str,
                                    help="Net mask of interface")

    # server group
    create_server_parent = argparse.ArgumentParser(add_help=False)
    create_server_parent.add_argument("--domain-name", help="VM domain name")

    # power consuming assets group
    create_power_parent = argparse.ArgumentParser(add_help=False)
    create_power_parent.add_argument(
        "--power-source",
        type=int,
        default=ISystemEnvironment.wallpower_volt_standard())
    create_power_parent.add_argument(
        "--power-consumption",
        required=True,
        type=int,
        help="Power consumption in Watts",
    )

    ## > Add type-specific args < ##

    create_subp = create_asset_group.add_subparsers()

    ## OUTLET
    create_outlet_action = create_subp.add_parser(
        "outlet",
        help="Create a Simple outlet asset",
        parents=[create_asset_parent])

    ## PDU
    create_pdu_action = create_subp.add_parser(
        "pdu",
        help="Create PDU asset",
        parents=[create_asset_parent, create_volt_parent, create_snmp_parent],
    )

    ## UPS
    create_ups_action = create_subp.add_parser(
        "ups",
        help="Create UPS asset",
        parents=[
            create_asset_parent, create_snmp_parent,
            get_ups_command_parent()
        ],
    )

    create_ups_action.add_argument(
        "--power-source",
        help="Asset Voltage",
        type=int,
        default=ISystemEnvironment.wallpower_volt_standard(),
    )
    create_ups_action.add_argument(
        "--power-consumption",
        type=int,
        help="""Power consumption in Watts
          (how much UPS draws when not powering anything)""",
        default=24,
    )

    ## SERVER
    create_server_action = create_subp.add_parser(
        "server",
        help="Create a server asset (VM)",
        parents=[
            create_asset_parent,
            create_volt_parent,
            create_server_parent,
            create_power_parent,
        ],
    )

    create_server_action.add_argument(
        "--psu-num",
        type=int,
        default=1,
        help="Number of PSUs installed in the server")
    create_server_action.add_argument(
        "--psu-load",
        nargs="+",
        type=float,
        help="""PSU(s) load distribution (the downstream power is multiplied
        by the value, e.g.  for 2 PSUs if '--psu-load 0.5 0.5',
        load is divided equally) \n""",
    )

    create_server_action.add_argument(
        "--psu-power-consumption",
        nargs="+",
        type=int,
        default=6,
        help="""Power consumption of idle PSU \n""",
    )

    create_server_action.add_argument(
        "--psu-power-source",
        nargs="+",
        type=int,
        default=ISystemEnvironment.wallpower_volt_standard(),
        help="""PSU Voltage \n""",
    )

    ## SERVER-BMC
    create_server_bmc_action = create_subp.add_parser(
        "server-bmc",
        help="Create a server asset (VM) that supports IPMI interface",
        parents=[
            create_asset_parent,
            create_volt_parent,
            create_server_parent,
            create_power_parent,
        ],
    )

    create_server_bmc_action.add_argument(
        "--user",
        type=str,
        default="ipmiusr",
        help="BMC-enabled server: IPMI admin user",
    )
    create_server_bmc_action.add_argument(
        "--password",
        type=str,
        default="test",
        help="BMC-enabled server: IPMI user password",
    )
    create_server_bmc_action.add_argument("--host",
                                          type=str,
                                          default="localhost",
                                          help="IPMI interface host")
    create_server_bmc_action.add_argument("--port",
                                          type=int,
                                          default=9001,
                                          help="IPMI interface port")

    create_server_bmc_action.add_argument(
        "--interface",
        type=str,
        default="",
        help="Network interface attached to the server",
    )
    create_server_bmc_action.add_argument(
        "--vmport",
        type=int,
        default=9002,
        help="IPMI serial VM interface for channel 15 (the system interface)",
    )

    create_server_bmc_action.add_argument(
        "--storcli-port",
        type=int,
        default=50000,
        help="Storcli websocket port used to establish a connection with a vm",
    )

    create_server_bmc_action.add_argument(
        "--sensor-def",
        type=str,
        help="""File containing sensor definitions 
        (defaults to sensors.json file in enginecore/enginecore/model/presets)""",
    )

    create_server_bmc_action.add_argument(
        "--storage-def",
        type=str,
        help="""File containing storage definitions 
        (defaults to storage.json file in enginecore/enginecore/model/presets)
        """,
    )

    create_server_bmc_action.add_argument(
        "--storage-states",
        type=str,
        help="""File containing storage state mappings (.JSON)
        """,
    )

    ## STATIC
    create_static_action = create_subp.add_parser(
        "static",
        help="Add static (dummy) asset",
        parents=[create_asset_parent, create_volt_parent, create_power_parent],
    )

    create_static_action.add_argument(
        "--img-url", help="URL of the image displayed on the frontend")

    ## LAMP
    create_lamp_action = create_subp.add_parser(
        "lamp",
        help="Used for power demonstrations",
        parents=[create_asset_parent, create_volt_parent, create_power_parent],
    )

    create_outlet_action.set_defaults(
        validate=lambda args: validate_key(args["asset_key"]),
        func=lambda args: sys_modeler.create_outlet(args["asset_key"], args),
    )

    create_pdu_action.set_defaults(
        validate=lambda args: validate_key(args["asset_key"]),
        func=lambda args: sys_modeler.create_pdu(args["asset_key"], args),
    )

    create_ups_action.set_defaults(
        validate=lambda args: validate_key(args["asset_key"]),
        func=lambda args: sys_modeler.create_ups(args["asset_key"], args),
    )

    create_server_action.set_defaults(
        validate=lambda args:
        [validate_key(args["asset_key"]),
         validate_server(args)],
        func=lambda args: sys_modeler.create_server(args["asset_key"], args),
    )

    create_server_bmc_action.set_defaults(
        validate=lambda args: [validate_key(args["asset_key"])],
        func=lambda args: sys_modeler.create_server(
            args["asset_key"],
            args,
            server_variation=sys_modeler.ServerVariations.ServerWithBMC,
        ),
    )

    create_static_action.set_defaults(
        validate=lambda args: validate_key(args["asset_key"]),
        func=lambda args: sys_modeler.create_static(args["asset_key"], args),
    )

    create_lamp_action.set_defaults(
        validate=lambda args: validate_key(args["asset_key"]),
        func=lambda args: sys_modeler.create_lamp(args["asset_key"], args),
    )
Esempio n. 12
0
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)
Esempio n. 13
0
 def _handle_voltage_request(self, details):
     """ "Handle voltage update"""
     ISystemEnvironment.set_voltage(details["payload"]["voltage"])
Esempio n. 14
0
 def _handle_ambient_request(self, details):
     """ "Handle ambient changes request"""
     ISystemEnvironment.set_ambient(details["payload"]["degrees"])
Esempio n. 15
0
 def _handle_mains_request(self, details):
     """Wallpower update request"""
     if details["payload"]["mains"] == 0:
         ISystemEnvironment.power_outage()
     else:
         ISystemEnvironment.power_restore()