def device_location(rack_id, board_id=None, device_id=None): # pylint: disable=unused-argument """ Get the location of a device. This command is supported for PLC. Other devicebus types (IPMI, Redfish, SNMP, RS485, I2C) are not supported, so 'unknown' is returned. Args: rack_id (str): the id of the rack where the target board resides board_id (str): the board id to get location for. non-PLC boards are not supported. device_id (str): the device id to get location for. non-PLC devices are not supported. Returns: The location of device, if known. Raises: Returns a 500 error if the location command fails. """ if device_id is not None: (board_id, device_id) = check_valid_board_and_device(board_id, device_id) if device_id > 0xFFFF: raise SynseException('Device number must be <= 0xFFFF') else: board_id = check_valid_board(board_id) try: # add validation on the board by finding its device instance. if this # is not a valid board, we raise an exception, as there is no valid # location for it get_device_instance(board_id) except Exception as e: raise e # physical (rack) location is not yet implemented in v1 physical_location = { _s_.LOC_HORIZONTAL: _s_.LOC_UNKNOWN, _s_.LOC_VERTICAL: _s_.LOC_UNKNOWN, _s_.LOC_DEPTH: _s_.LOC_UNKNOWN } if device_id is not None: return make_json_response({ _s_.PHYSICAL_LOC: physical_location, _s_.CHASSIS_LOC: get_chassis_location(device_id) }) return make_json_response({_s_.PHYSICAL_LOC: physical_location})
def host_info(rack_id, board_id, device_id): """ Get hostname(s) and ip address(es) for a given host. The host must be of type 'system'. Args: rack_id (str): the id of the rack where the target board resides. board_id (str): the board id to get host info for. device_id (str): the device id to get host info for. Returns: Hostname(s) and IP address(es) for the specified system. Raises: Returns a 500 error if the host info command fails. """ board_id, device_id = check_valid_board_and_device(board_id, device_id) cmd = current_app.config['CMD_FACTORY'].get_host_info_command({ _s_.BOARD_ID: board_id, _s_.DEVICE_ID: device_id, _s_.DEVICE_TYPE: get_device_type_code(const.DEVICE_SYSTEM), _s_.DEVICE_NAME: const.DEVICE_SYSTEM, _s_.RACK_ID: rack_id }) device = get_device_instance(board_id) response = device.handle(cmd) return make_json_response(response.get_response_data())
def asset_info(rack_id, board_id, device_id): """ Get asset information for a given board and device. Args: rack_id (str): the id of the rack where the target board resides. board_id (str): the board number to get asset information for. device_id (str): the device number to get asset information for (the device must have a device_type of 'system'). Returns: Asset information about the given device. Raises: Returns a 500 error if the asset command fails. """ board_id, device_id = check_valid_board_and_device(board_id, device_id) cmd = current_app.config['CMD_FACTORY'].get_asset_command({ _s_.BOARD_ID: board_id, _s_.DEVICE_ID: device_id, _s_.DEVICE_TYPE: get_device_type_code(const.DEVICE_SYSTEM), _s_.RACK_ID: rack_id }) device = get_device_instance(board_id) response = device.handle(cmd) return make_json_response(response.get_response_data())
def get_board_devices(rack_id, board_id=None): """ Query a specific rack or board and provide the active devices on the found board(s). Args: rack_id (str): the id of the rack to scan. board_id (str): the board id to scan. if the upper byte is 0x80 then all boards will be scanned. Returns: Active devices, numbers and types from the queried board(s). Raises: Returns a 500 error if the scan command fails. """ # if there is no board_id, we are doing a scan on a rack. # FIXME: since scan by the rack is not supported yet, (v 1.3) we will # determine the rack results by filtering on the 'scanall' results. if board_id is None: scanall = scan_all() data = json.loads(scanall.data) for rack in data['racks']: if rack['rack_id'] == rack_id: return make_json_response({'racks': [rack]}) raise SynseException('No rack found with id: {}'.format(rack_id)) board_id = check_valid_board(board_id) # first, attempt to get the info from the scan cache. _cache = get_scan_cache() if _cache: _cache = _filter_cache_meta(_cache) for rack in _cache['racks']: if rack['rack_id'] == rack_id: for board in rack['boards']: if int(board['board_id'], 16) == board_id: return make_json_response({ 'racks': [{ 'rack_id': rack['rack_id'], 'ip_addresses': rack.get('ip_addresses', []), 'hostnames': rack.get('hostnames', []), 'boards': [board] }] }) break cmd = current_app.config['CMD_FACTORY'].get_scan_command({ _s_.RACK_ID: rack_id, _s_.BOARD_ID: board_id }) device = get_device_instance(board_id) response = device.handle(cmd) return make_json_response(response.get_response_data())
def get_board_version(rack_id, board_id): """ Get the version information for the specified board. Args: rack_id (str): the rack id associated with the board. board_id (str): the board id to get version for. Returns: The version of the hardware and firmware for the given board. Raises: Returns a 500 error if the version command fails. """ board_id = check_valid_board(board_id) cmd = current_app.config['CMD_FACTORY'].get_version_command({ _s_.RACK_ID: rack_id, _s_.BOARD_ID: board_id }) device = get_device_instance(board_id) response = device.handle(cmd) return make_json_response(response.get_response_data())
def power_control(power_action='status', rack_id=None, board_id=None, device_id=None, device_type='power'): """ Power control for the given rack, board, and device. Args: power_action (str): may be on/off/cycle/status and corresponds to the action to take. rack_id (str): the id of the rack which contains the board to accept the power control command. board_id (str): the id of the board which contains the device that accepts power control commands. device_id (str): the id of the device which accepts power control commands. device_type (str): the type of device to accept power control command for. (default: power) Returns: Power status of the given device. Raises: Returns a 500 error if the power command fails. """ board_id, device_id = check_valid_board_and_device(board_id, device_id) if rack_id.lower() in [ _s_.PWR_ON, _s_.PWR_OFF, _s_.PWR_CYCLE, _s_.PWR_STATUS ]: # FIXME: (etd) - we should probably depricate the 'old' form described here # for both cleanliness and API unity. # for backwards-compatibility, we allow the command to come in as: # power_action/board_id/device_id # therefore, if we see a power action in the rack_id field, then # we need to rearrange the parameters power_action = rack_id cmd = current_app.config['CMD_FACTORY'].get_power_command({ _s_.BOARD_ID: board_id, _s_.DEVICE_ID: device_id, _s_.DEVICE_TYPE: get_device_type_code(device_type.lower()), _s_.POWER_ACTION: power_action }) device = get_device_instance(board_id) response = device.handle(cmd) return make_json_response(response.get_response_data())
def fan_control(rack_id, board_id, device_id, fan_speed=None): """ Control a fan on a system or Vapor Chamber. System fan may only be polled for status unless explicitly supported. Args: rack_id (str): the rack id to control fan for. board_id (str): the board id to control fan for. device_id (str): the device id to control fan for. fan_speed (str): the speed to set the fan to. Returns: The status of the fan; fan speed in RPM. Raises: Returns a 500 error if the fan command fails. """ board_id, device_id = check_valid_board_and_device(board_id, device_id) # if we are reading the fan speed only, forward on to the device_read method and # pass along response if fan_speed is None: return read_device(rack_id, const.DEVICE_FAN_SPEED, board_id, device_id) # convert fan speed to int if fan_speed is not None: try: int(fan_speed) except ValueError as e: logger.error('Fan: Error converting fan_speed: %s', str(fan_speed)) raise SynseException( 'Error converting fan_speed to integer ({}).'.format(e)) cmd = current_app.config['CMD_FACTORY'].get_fan_command({ _s_.BOARD_ID: board_id, _s_.DEVICE_ID: device_id, _s_.DEVICE_TYPE: get_device_type_code(const.DEVICE_FAN_SPEED), _s_.DEVICE_NAME: const.DEVICE_FAN_SPEED, _s_.FAN_SPEED: fan_speed }) device = get_device_instance(board_id) response = device.handle(cmd) return make_json_response(response.get_response_data())
def boot_target(rack_id, board_id, device_id, target=None): """ Get or set the boot target for a given board and device. Args: rack_id (str): the id of the rack where the target board resides. board_id (str): the board id to get/set boot target for. device_id (str): the device id to get/set boot target for (the device must have a device_type of 'system'). target (str): the boot target to choose. if not specified, the default behavior is to get the boot target info. valid values for boot target are 'pxe', 'hdd', and 'no_override'. Returns: Boot target of the device. Raises: Returns a 500 error if the boot target command fails. """ board_id, device_id = check_valid_board_and_device(board_id, device_id) if target is not None and target not in [ _s_.BT_PXE, _s_.BT_HDD, _s_.BT_NO_OVERRIDE ]: logger.error( 'Boot Target: Invalid boot target specified: {} board_id: {} ' 'device_id: {}'.format(target, board_id, device_id)) raise SynseException('Invalid boot target specified.') cmd = current_app.config['CMD_FACTORY'].get_boot_target_command({ _s_.BOARD_ID: board_id, _s_.DEVICE_ID: device_id, _s_.DEVICE_TYPE: get_device_type_code(const.DEVICE_SYSTEM), _s_.BOOT_TARGET: target if target is not None else 'status', _s_.RACK_ID: rack_id }) device = get_device_instance(board_id) response = device.handle(cmd) return make_json_response(response.get_response_data())
def _lookup_device_uuid(board_id): """ Lookup the UUID of a devicebus instance for a given board id/alias. Args: board_id (int | str): board id, or devicebus alias, to look up. Returns: str: the UUID of the devicebus interface if found. None: no devicebus interface matched the board id/alias. """ device = get_device_instance(board_id) # unsupported device returns None if not isinstance(device, (PLCDevice, IPMIDevice, RS485Device, I2CDevice, SnmpDevice, RedfishDevice)): return None uuid = None if device: uuid = str(device.device_uuid) return uuid
def read_device(rack_id, device_type, board_id, device_id): """ Get a device reading for the specified device type on the specified device. Args: rack_id (str): the id of the rack where target board & device reside. device_type (str): corresponds to the type of device to get a reading for. It must match the actual type of device that is present on the bus, and is used to interpret the raw device reading. board_id (str): the id of the board where the target device resides. device_id (str): specifies which device should be polled for device reading. Returns: Interpreted and raw device reading, based on the specified device type. Raises: Returns a 500 error if the read command fails. """ board_id, device_id = check_valid_board_and_device(board_id, device_id) cmd = current_app.config['CMD_FACTORY'].get_read_command({ _s_.RACK_ID: rack_id, _s_.BOARD_ID: board_id, _s_.DEVICE_ID: device_id, _s_.DEVICE_TYPE: get_device_type_code(device_type.lower()), _s_.DEVICE_TYPE_STRING: device_type.lower() }) device = get_device_instance(board_id) response = device.handle(cmd) return make_json_response(response.get_response_data())
def led_control(rack_id, board_id, device_id, led_state=None, led_color=None, blink_state=None): """ Control an LED on system or Vapor Chamber wedge rack. System LEDs may only be turned on/off. Vapor Chamber wedge rack supports color. Args: rack_id (str): the rack id to control LED for. board_id (str): the board id to control LED for. IPMI boards only support on/off. device_id (str): the device id to control LED for. IPMI devices only support on/off. led_state (str): the state to set LED to (on/off/blink for PLC, on/off for IPMI). led_color (str): the hex RGB color to set LED to (for PLC wedge LED only). blink_state (str): the blink state (blink|steady|no_override) for PLC wedge LED only. Returns: LED state for chassis LED; LED state, color and blink state for PLC wedge LED. Raises: Returns a 500 error if the LED command fails. """ board_id, device_id = check_valid_board_and_device(board_id, device_id) if led_state not in [_s_.LED_ON, _s_.LED_OFF, _s_.LED_NO_OVERRIDE, None]: logger.error( 'Invalid LED state {} provided for LED control.'.format(led_state)) raise SynseException('Invalid LED state provided for LED control.') if led_color is not None and led_color != _s_.LED_NO_OVERRIDE: try: led_color_int = int(led_color, 16) if (led_color_int < 0x000000) or (led_color_int > 0xffffff): raise ValueError( 'LED Color must be between 0x000000 and 0xffffff.') except ValueError as e: raise SynseException('Invalid LED color specified. ({})'.format( e.message)) if blink_state is not None and blink_state not in [ _s_.LED_BLINK, _s_.LED_STEADY, _s_.LED_NO_OVERRIDE ]: raise SynseException('Invalid blink state specified for LED.') cmd = current_app.config['CMD_FACTORY'].get_led_command({ _s_.BOARD_ID: board_id, _s_.DEVICE_ID: device_id, _s_.DEVICE_TYPE: get_device_type_code(const.DEVICE_LED), _s_.DEVICE_TYPE_STRING: const.DEVICE_LED, _s_.DEVICE_NAME: const.DEVICE_LED, _s_.RACK_ID: rack_id, _s_.LED_STATE: led_state, _s_.LED_COLOR: led_color, _s_.LED_BLINK_STATE: blink_state, }) device = get_device_instance(board_id) response = device.handle(cmd) return make_json_response(response.get_response_data())