Example #1
0
 def __init__(self, serial_reader=None, board_id=0x00000000, data_bytes=None, sequence=0x01,
              device_type=0xFF, raw_data=None, device_id=0xFFFF):
     """ Three ways to initialize the command - it may be read, when expected,
     via a serial reader (via serial_reader - e.g. for testing with the
     emulator). Alternately, a byte buffer (data_bytes) may be given to the
     constructor, which is deserialized and populates the appropriate fields
     of the object. Finally, a DeviceWriteCommand may be constructed from a
     board_id, device_type, raw_value, and device_id (and sequence number) - this is what
     is most likely to be used by a client application (e.g. the flask server).
     """
     if serial_reader is not None:
         super(DeviceWriteCommand, self).__init__(serial_reader=serial_reader)
     elif data_bytes is not None:
         super(DeviceWriteCommand, self).__init__(data_bytes=data_bytes)
     else:
         data_val = [ord('W')]
         if raw_data is not None and isinstance(raw_data, basestring):
             # TODO: this is a temporary workaround until fan motor pole is settled
             if device_type == get_device_type_code('fan_speed'):
                 data_val.append(0xFF)
             for c in raw_data:
                 data_val.append(ord(c))
         else:
             raise BusDataException('Invalid data provided to be written to device.')
         super(DeviceWriteCommand, self).__init__(sequence=sequence, device_type=device_type, board_id=board_id,
                                                  device_id=device_id, data=data_val)
Example #2
0
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)
Example #3
0
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)
Example #4
0
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)
Example #5
0
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)
Example #6
0
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)
Example #7
0
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)
Example #8
0
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)
Example #9
0
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)
Example #10
0
    def _fan(self, command):
        """ Fan speed control command for a given board and device.

        Args:
            command (Command): the command issued by the OpenDCRE endpoint
                containing the data and sequence for the request.

        Returns:
            Response: a Response object corresponding to the incoming Command
                object, containing the data from the fan response.
        """
        with self._lock:
            bus = self._get_bus()

            # get the command data out from the incoming command
            board_id = command.data['board_id']
            device_id = command.data['device_id']
            device_type = command.data['device_type']
            fan_speed = command.data['fan_speed']

            request = DeviceWriteCommand(
                board_id=board_id,
                device_id=device_id,
                device_type=device_type,
                raw_data=fan_speed,
                sequence=command.sequence
            )
            bus.write(request.serialize())
            bus.flush()

            logger.debug('>>Fan_Speed: {}'.format([hex(x) for x in request.serialize()]))
            response = None

            try:
                response = DeviceWriteResponse(
                    serial_reader=bus,
                    expected_sequence=request.sequence
                )
                logger.debug('<<Fan_Speed: {}'.format([hex(x) for x in response.serialize()]))

            except BusTimeoutException:
                raise OpenDCREException('Fan command bus timeout.'), None, sys.exc_info()[2]
            except (BusDataException, ChecksumException):
                response = self._retry_command(bus, request, DeviceWriteResponse)

        # get raw value to ensure remote device took the write.
        try:
            device_raw = str(''.join([chr(x) for x in response.data]))
        except (ValueError, TypeError):
            # abort if unable to convert to int (ValueError), unable to convert to chr (TypeError)
            raise OpenDCREException('Fan control: Error converting device response.'), None, sys.exc_info()[2]
        if device_raw == 'W1':
            c = Command(
                cmd_id=cid.READ,
                data={
                    'board_id': board_id,
                    'device_id': device_id,
                    'device_type': get_device_type_code(const.DEVICE_FAN_SPEED),
                    'device_type_string': const.DEVICE_FAN_SPEED
                },
                sequence=next(self._count)
            )
            return self._read(c)
        else:
            raise OpenDCREException('Error writing to device {} on board {}'.format(hex(device_id), hex(board_id)))