示例#1
0
async def boot_target_route(request, rack, board, device):
    """Endpoint to read/write boot target device data.

    This route is an alias for the core `read` functionality when there
    are no valid query parameters specified. It is an alias for the core
    `write` functionality when there are valid query parameters specified.

    Supported Query Parameters:
        target: The boot target to set (hdd|pxe)

    Args:
        request (sanic.request.Request): The incoming request.
        rack (str): The rack which the system resides on.
        board (str): The board which the system resides on.
        device (str): The system device.

    Returns:
        sanic.response.HTTPResponse: The endpoint response.
    """
    await validate.validate_device_type(const.BOOT_TARGET_TYPES, rack, board,
                                        device)

    # Get the valid query parameters. If unsupported query parameters
    # are specified, this will raise an error.
    qparams = validate.validate_query_params(request.raw_args, 'target')
    param_target = qparams.get('target')

    # If any of the parameters are specified, this will be a write request
    # using those parameters.
    if param_target is not None:
        logger.debug(
            _('Boot target alias route: writing (query parameters: {})').
            format(qparams))

        if param_target not in const.boot_targets:
            raise errors.InvalidArgumentsError(
                _('Invalid boot target "{}". Must be one of: {}').format(
                    param_target, const.boot_targets))

        data = {'action': 'target', 'raw': param_target}
        transaction = await commands.write(rack, board, device, data)
        return transaction.to_json()

    # Otherwise, we just read from the device.
    else:
        logger.debug(_('Boot target alias route: reading'))
        reading = await commands.read(rack, board, device)
        return reading.to_json()
示例#2
0
async def power_route(request, rack, board, device):
    """Endpoint to read/write power device data.

    This route is an alias for the core `read` functionality when there
    are no valid query parameters specified. It is an alias for the core
    `write` functionality when there are valid query parameters specified.

    Supported Query Parameters:
        state: The power state to set (on|off|cycle)

    Args:
        request (sanic.request.Request): The incoming request.
        rack (str): The rack which the power device resides on.
        board (str): The board which the power device resides on.
        device (str): The power device.

    Returns:
        sanic.response.HTTPResponse: The endpoint response.
    """
    await validate.validate_device_type(const.TYPE_POWER, rack, board, device)

    # Get the valid query parameters. If unsupported query parameters
    # are specified, this will raise an error.
    qparams = validate.validate_query_params(request.raw_args, 'state')
    param_state = qparams.get('state')

    # If any of the parameters are specified, this will be a write request
    # using those parameters.
    if param_state is not None:
        logger.debug(
            _('Power alias route: writing (query parameters: {})').format(
                qparams))

        if param_state not in const.power_actions:
            raise errors.InvalidArgumentsError(
                _('Invalid power state "{}". Must be one of: {}').format(
                    param_state, const.power_actions))

        data = {'action': 'state', 'raw': param_state}
        transaction = await commands.write(rack, board, device, data)
        return transaction.to_json()

    # Otherwise, we just read from the device.
    else:
        logger.debug(_('Power alias route: reading'))
        reading = await commands.read(rack, board, device)
        return reading.to_json()
示例#3
0
async def lock_route(request, rack, board, device):  # pylint: disable=unused-argument
    """Endpoint to read/write lock device data.

    This route is an alias for the core `read` functionality when there
    are no valid query parameters specified. It is an alias for the core
    `write` functionality when there are valid query parameters specified.

    Args:
        request (sanic.request.Request): The incoming request.
        rack (str): The rack which the lock resides on.
        board (str): The board which the lock resides on.
        device (str): The lock device.

    Returns:
        sanic.response.HTTPResponse: The endpoint response.
    """
    await validate.validate_device_type(const.LOCK_TYPES, rack, board, device)

    # Get the valid query parameters. If unsupported query parameters
    # are specified, this will raise an error.
    qparams = validate.validate_query_params(request.raw_args, 'action')
    param_action = qparams.get('action')

    # If any of the parameters are specified, this will be a write request
    # using those parameters.
    if param_action is not None:
        logger.debug(
            _('Lock alias route: writing (query parameters: {})').format(
                qparams))

        if param_action not in const.lock_actions:
            raise errors.InvalidArgumentsError(
                _('Invalid boot target "{}". Must be one of: {}').format(
                    param_action, const.lock_actions))

        data = {
            'action': param_action,
        }
        transaction = await commands.write(rack, board, device, data)
        return transaction.to_json()

    # Otherwise, we just read from the device.
    else:
        logger.debug(_('Lock alias route: reading'))
        reading = await commands.read(rack, board, device)
        return reading.to_json()
示例#4
0
async def read_cached_route(request):
    """Get cached readings from the configured plugins.

    Query Parameters:
        start: An RFC3339 or RFC3339Nano formatted timestamp which specifies a
            starting bound on the cache data to return. If no timestamp is
            specified, there will not be a starting bound.
        end: An RFC3339 or RFC3339Nano formatted timestamp which specifies an
            ending bound on the cache data to return. If no timestamp is
            specified, there will not be an ending bound.
    """
    qparams = validate.validate_query_params(request.raw_args, 'start', 'end')
    start, end = qparams.get('start'), qparams.get('end')

    # define the streaming function
    async def response_streamer(response):
        async for reading in commands.read_cached(start, end):  # pylint: disable=not-an-iterable
            await response.write(reading.dump())

    return stream(response_streamer, content_type='application/json')
示例#5
0
async def scan_route(request, rack=None, board=None):
    """Get meta-information about all racks, boards, and devices from all
    configured plugins.

    This aggregates the known configured racks, boards, and devices for
    each of the running plugins providing information to Synse Server. The
    scan response provides a high-level view of which devices exist in the
    system and where they exist (e.g. how they are addressable). With a scan
    response, a user should have enough information to perform any subsequent
    command (e.g. read, write) for a given device.

    Supported Query Parameters:
        force: Forces a re-scan if 'true', otherwise does nothing.

    Args:
        request (sanic.request.Request): The incoming request.
        rack (str): The identifier of the rack to scan. If specified, this
            filters the complete scan result to only return the subset of
            scan information pertinent to the specific rack.
        board (str): The identifier of the board to scan. If specified, in
            conjunction with a rack identifier, this filters the complete
            scan result to only return the scan information for the specified
            board on the specified rack.

    Returns:
        sanic.response.HTTPResponse: The endpoint response.
    """
    qparams = validate.validate_query_params(request.raw_args, 'force')

    param_force = qparams.get('force')

    force = False
    if param_force is not None:
        force = param_force.lower() == 'true'
    logger.debug(_('Forcing re-scan? {}').format(force))

    response = await commands.scan(rack=rack, board=board, force=force)
    return response.to_json()
示例#6
0
async def fan_route(request, rack, board, device):
    """Endpoint to read/write fan device data.

    This route is an alias for the core `read` functionality when there
    are no valid query parameters specified. It is an alias for the core
    `write` functionality when there are valid query parameters specified.

    Supported Query Parameters:
        speed: The fan speed to set, in RPM.
        speed_percent: The fan speed to set, in percent.

    Args:
        request (sanic.request.Request): The incoming request.
        rack (str): The rack which the fan device resides on.
        board (str): The board which the fan device resides on.
        device (str): The fan device.

    Returns:
        sanic.response.HTTPResponse: The endpoint response.
    """
    await validate.validate_device_type(const.TYPE_FAN, rack, board, device)

    # Get the valid query parameters. If unsupported query parameters
    # are specified, this will raise an error.
    qparams = validate.validate_query_params(
        request.raw_args,
        'speed',  # speed in rpm
        'speed_percent'  # speed of 0 (off) or 10% to 100%
    )

    param_speed_rpm = qparams.get('speed')
    param_speed_percent = qparams.get('speed_percent')

    # Only one of 'speed' and 'speed_percent' can be specified at a time.
    # TODO (etd): this could be generalized and incorporated into the validation
    #   done above, e.g. validate_query_params(request.raw_args, OneOf(['speed', 'speed_percent']))
    if all((param_speed_rpm, param_speed_percent)):
        raise errors.InvalidArgumentsError(
            _('Invalid query params: Can only specify one of "speed" and '
              '"speed_percent", but both were given'))

    # If either of the parameters are specified, this will be a write request
    # using those parameters.
    if any((param_speed_rpm, param_speed_percent)):
        logger.debug(
            _('Fan alias route: writing (query parameters: {})').format(
                qparams))

        # Set the fan speed by RPM. No validation on the fan speed is done here,
        # as it is up to the underlying implementation to validate and fail as
        # needed. The max and min allowable speeds vary by fan motor.
        if param_speed_rpm:
            logger.debug(_('Setting fan speed by RPM'))
            data = {
                'action': 'speed',
                'raw': param_speed_rpm,
            }
            transaction = await commands.write(rack, board, device, data)
            return transaction.to_json()

        # Set the fan speed by percent (duty cycle). No validation on the fan
        # speed is done here, as it is up to the underlying implementation to
        # validate and fail as needed. The max and min allowable speeds vary
        # by fan motor.
        if param_speed_percent:
            logger.debug(_('Setting fan speed by percent'))
            data = {
                'action': 'speed_percent',
                'raw': param_speed_percent,
            }
            transaction = await commands.write(rack, board, device, data)
            return transaction.to_json()

    # Otherwise, we just read from the device.
    else:
        logger.debug(_('Fan alias route: reading'))
        reading = await commands.read(rack, board, device)
        return reading.to_json()
示例#7
0
async def led_route(request, rack, board, device):
    """Endpoint to read/write LED device data.

    This route is an alias for the core `read` functionality when there
    are no valid query parameters specified. It is an alias for the core
    `write` functionality when there are valid query parameters specified.

    Supported Query Parameters:
        state: The LED state to set (on|off|blink)
        color: The LED color to set. This must be a hexadecimal string
            between 000000 and ffffff.

    Args:
        request (sanic.request.Request): The incoming request.
        rack (str): The rack which the led device resides on.
        board (str): The board which the led device resides on.
        device (str): The LED device.

    Returns:
        sanic.response.HTTPResponse: The endpoint response.
    """
    await validate.validate_device_type(const.TYPE_LED, rack, board, device)

    # Get the valid query parameters. If unsupported query parameters
    # are specified, this will raise an error.
    qparams = validate.validate_query_params(request.raw_args, 'state',
                                             'color')
    param_state = qparams.get('state')
    param_color = qparams.get('color')

    # If any of the parameters are specified, this will be a write request
    # using those parameters.
    if any((param_state, param_color)):
        logger.debug(
            _('LED alias route: writing (query parameters: {})').format(
                qparams))
        data = []

        if param_state:
            if param_state not in const.led_states:
                raise errors.InvalidArgumentsError(
                    _('Invalid LED state "{}". Must be one of: {}').format(
                        param_state, const.led_states))

            data.append({'action': 'state', 'raw': param_state})

        if param_color:
            try:
                assert 0x000000 <= int(param_color, 16) <= 0xFFFFFF
            except Exception as e:
                raise errors.InvalidArgumentsError(
                    _('Invalid color value ({}). Must be a hexadecimal '
                      'string between 000000 and FFFFFF').format(
                          param_color)) from e

            data.append({'action': 'color', 'raw': param_color})

        logger.debug(_('LED data to write: {}').format(data))
        transactions = None
        for d in data:
            t = await commands.write(rack, board, device, d)
            if not transactions:
                transactions = t
            else:
                transactions.data.extend(t.data)

        return transactions.to_json()

    # Otherwise, we just read from the device.
    else:
        logger.debug(_('LED alias route: reading'))
        reading = await commands.read(rack, board, device)
        return reading.to_json()
示例#8
0
def test_validate_query_params_invalid(params, valid):
    """Test validating query parameters when invalid parameters are given."""
    with pytest.raises(errors.InvalidArgumentsError):
        validate.validate_query_params(params, *valid)
示例#9
0
def test_validate_query_params(params, valid, expected):
    """Test validating query parameters successfully."""
    assert validate.validate_query_params(params, *valid) == expected