def host_info(rack_id, board_num, device_num): """ Get hostname and ip address for a given host (of type 'system'. This uses the PLC TTY to login to the server, and retrieve the hostname[s] and ip address[es] Args: rack_id: The id of the rack where the target board resides board_num: The board number to get host info for. device_num: The device number to get host info for. Returns: hostname(s) and IP address(es) """ board_num, device_num = check_valid_board_and_device(board_num, device_num) cmd = current_app.config['CMD_FACTORY'].get_host_info_command({ 'board_id': board_num, 'device_id': device_num, 'device_type': get_device_type_code(const.DEVICE_SYSTEM), 'device_name': const.DEVICE_SYSTEM }) device = get_device_instance(board_num) response = device.handle(cmd) return jsonify(response.data)
def boot_target(rack_id, board_num, device_num, target=None): """ Get or set boot target for a given board and device. Args: rack_id: The id of the rack where the target board resides board_num: The board number to get/set boot target for. device_num: The device number to get/set boot target for (must be system). target: The boot target to choose, or, if None, just get info. Returns: Boot target of the device. """ board_num, device_num = check_valid_board_and_device(board_num, device_num) if target is not None and target not in ['pxe', 'hdd', 'no_override']: logger.error( 'Boot Target: Invalid boot target specified: %s board_num: %s device_num: %s', target, board_num, device_num) raise OpenDCREException('Invalid boot target specified.') cmd = current_app.config['CMD_FACTORY'].get_boot_target_command({ 'board_id': board_num, 'device_id': device_num, 'device_type': get_device_type_code(const.DEVICE_SYSTEM), 'boot_target': target if target is not None else 'status' }) device = get_device_instance(board_num) response = device.handle(cmd) return jsonify(response.data)
def asset_info(rack_id, board_num, device_num): """ Get asset information for a given board and device. Args: rack_id: The id of the rack where the target board resides board_num: The board number to get asset information for. device_num: The device number to get asset information for (must be system). Returns: Asset information about the given device. """ board_num, device_num = check_valid_board_and_device(board_num, device_num) cmd = current_app.config['CMD_FACTORY'].get_asset_command({ 'board_id': board_num, 'device_id': device_num, 'device_type': get_device_type_code(const.DEVICE_SYSTEM), }) device = get_device_instance(board_num) response = device.handle(cmd) return jsonify(response.data)
def get_board_version(rack_id, board_num): """ Get board version given the specified board number. Args: rack_id (str): the rack id associated with the board (currently unused). board_num (str): the board number 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_num = check_valid_board(board_num) cmd = current_app.config['CMD_FACTORY'].get_version_command({ 'rack_id': rack_id, 'board_id': board_num }) device = get_device_instance(board_num) response = device.handle(cmd) return jsonify(response.data)
def device_location(rack_id, board_num=None, device_num=None): """ Get location of a device via PLC. IPMI not supported, so unknown is returned. Args: rack_id: The id of the rack where the target board resides board_num: The board number to get location for. IPMI boards not supported. device_num: The device number to get location for. IPMI devices not supported. Returns: Location of device. """ if device_num is not None: (board_num, device_num) = check_valid_board_and_device(board_num, device_num) if device_num > 0xFFFF: raise OpenDCREException('Device number must be <= 0xFFFF') else: board_num = check_valid_board(board_num) 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_num) except Exception as e: raise e # physical (rack) location is not yet implemented in v1 physical_location = { 'horizontal': 'unknown', 'vertical': 'unknown', 'depth': 'unknown' } if device_num is not None: return jsonify({ 'physical_location': physical_location, 'chassis_location': get_chassis_location(device_num) }) else: return jsonify({'physical_location': physical_location})
def get_board_devices(rack_id, board_num=None): """ Query a specific board, given the board id, and provide the active devices on that board. Args: rack_id (str): The id of the rack where the target board resides board_num (str): the board number to dump. If the upper byte is 0x80 then all boards on the bus will be scanned. Returns: Active devices, numbers and types from the given board(s). Raises: Returns a 500 error if the scan command fails. """ # if there is no board_num, 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_num is None: scanall = scan_all() data = json.loads(scanall.data) for rack in data['racks']: if rack['rack_id'] == rack_id: return jsonify({'racks': [rack]}) raise OpenDCREException('No rack found with id: {}'.format(rack_id)) board_num = check_valid_board(board_num) """ FIXME: temporarily disabled 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_num: return jsonify({'boards': [board]}) else: break """ cmd = current_app.config['CMD_FACTORY'].get_scan_command({ 'rack_id': rack_id, 'board_id': board_num }) device = get_device_instance(board_num) response = device.handle(cmd) return jsonify(response.data)
def fan_control(rack_id, board_num, device_num, fan_speed=None): """ Control fan on system or Vapor Chamber. System fan may only be polled for status unless explicitly supported. Args: rack_id: The rack id to control fan for. board_num: The board number to control fan for. device_num: The device number to control fan for. fan_speed: The speed to set fan to. Returns: fan speed in rpms """ board_id, device_id = check_valid_board_and_device(board_num, device_num) # 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, 'fan_speed', board_num, device_num) # convert fan speed to int if fan_speed is not None: try: fan_speed_int = int(fan_speed) # FIXME: we can move this to individual device instances which will give us finer-toothed control if definitions.MAX_FAN_SPEED < fan_speed_int or definitions.MIN_FAN_SPEED > fan_speed_int: raise ValueError('Fan speed out of acceptable range.') except ValueError as e: logger.error('Location: Error converting fan_speed: %s', str(fan_speed)) raise OpenDCREException( 'Error converting fan_speed to integer ({}).'.format(e)) cmd = current_app.config['CMD_FACTORY'].get_fan_command({ 'board_id': board_id, 'device_id': device_id, 'device_type': get_device_type_code(const.DEVICE_FAN_SPEED), 'device_name': const.DEVICE_FAN_SPEED, 'fan_speed': fan_speed }) device = get_device_instance(board_id) response = device.handle(cmd) return jsonify(response.data)
def power_control(power_action='status', rack_id=None, board_num=None, device_num=None, device_type='power'): """ Power on/off/cycle/status for the given board and port 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_num (str): the id of the board which contains the device that accepts power control commands. device_num (str): the id of the device which accepts power control commands. device_type (str): the type of device to accept power control command for. Returns: Power status of the given device. Raises: Returns a 500 error if the power command fails. """ board_num, device_num = check_valid_board_and_device(board_num, device_num) if rack_id.lower() in ['on', 'off', 'cycle', 'status']: # 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({ 'board_id': board_num, 'device_id': device_num, 'device_type': get_device_type_code(device_type.lower()), 'power_action': power_action }) device = get_device_instance(board_num) response = device.handle(cmd) return jsonify(response.data)
def _lookup_by_id_range(board_id): """ Lookup the device(s) for a given board by the board id. Args: board_id (int): board id to look up Returns: dict: a dictionary of all the devices which map to the given board id range. """ device = get_device_instance(board_id) # unsupported device returns None if not isinstance(device, (PLCDevice, IPMIDevice, RedfishDevice)): return None return { uid: dev for uid, dev in current_app.config['DEVICES'].iteritems() if isinstance(dev, device.__class__) }
def read_device(rack_id, device_type, board_num, device_num): """ Get a device reading for the given board and port and device type. We could filter on the upper ID of board_num in case an unusual board number is provided; however, the bus should simply time out in these cases. 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_num (str): specifies which Pi hat to get the reading from device_num (str): specifies which device of the Pi hat 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_num, device_num = check_valid_board_and_device(board_num, device_num) cmd = current_app.config['CMD_FACTORY'].get_read_command({ 'board_id': board_num, 'device_id': device_num, 'device_type': get_device_type_code(device_type.lower()), 'device_type_string': device_type.lower() }) device = get_device_instance(board_num) response = device.handle(cmd) return jsonify(response.data)
def _chamber_led_control(board_num, device_num, led_state, rack_id, led_color, blink_state): """ Control chamber LED via PLC. Args: board_num: The board number of the LED controler for vapor_led. device_num: The device number of the LED controller for vapor_led. led_state: The state to set the specified LED to (on, off, no_override) rack_id: The ID of the rack whose LED segment is to be controlled (MIN_RACK_ID..MAX_RACK_ID) led_color: The RGB hex value of the color to set the LED to, or 'no_override'. blink_state: The blink state of the LED (blink, steady, no_override). """ cmd = current_app.config['CMD_FACTORY'].get_chamber_led_command({ 'board_id': board_num, 'device_id': device_num, 'device_type': get_device_type_code(const.DEVICE_VAPOR_LED), 'device_type_string': const.DEVICE_VAPOR_LED, 'device_name': const.DEVICE_VAPOR_LED, 'rack_id': rack_id, 'led_state': led_state, 'led_color': led_color, 'blink_state': blink_state, }) device = get_device_instance(board_num) response = device.handle(cmd) return jsonify(response.data)
def led_control(rack_id, board_num, device_num, led_state=None, led_color=None, blink_state=None): """ Control LED on system or wedge rack. System led may only be turned on/off. Wedge rack supports color Args: rack_id: The rack id to control led for. board_num: The board number to control led for. IPMI boards only support on/off. device_num: The device number to control led for. IPMI devices only support on/off. led_state: The state to set LED to (on/off for IPMI, on/off/blink for PLC). led_color: The hex RGB color to set LED to (for PLC wedge LED only). blink_state: 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. """ board_id, device_id = check_valid_board_and_device(board_num, device_num) if led_state not in ['on', 'off', 'no_override', None]: logger.error( 'Invalid LED state {} provided for LED control.'.format(led_state)) raise OpenDCREException('Invalid LED state provided for LED control.') if led_color is not None and led_color != '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 OpenDCREException('Invalid LED color specified. ({})'.format( e.message)) if blink_state is not None and blink_state not in [ 'blink', 'steady', 'no_override' ]: raise OpenDCREException('Invalid blink state specified for LED.') elif (led_color is not None) and (blink_state is not None): return _chamber_led_control(board_num=board_id, device_num=device_id, led_state=led_state, rack_id=rack_id, led_color=led_color, blink_state=blink_state) cmd = current_app.config['CMD_FACTORY'].get_led_command({ 'board_id': board_id, 'device_id': device_id, 'device_type': get_device_type_code(const.DEVICE_LED), 'device_type_string': const.DEVICE_LED, 'device_name': const.DEVICE_LED, 'rack_id': rack_id, 'led_state': led_state, 'led_color': led_color, 'blink_state': blink_state, }) device = get_device_instance(board_id) response = device.handle(cmd) return jsonify(response.data)