def write_emulator(device_name, channel, color, ledstate, blinkstate):
    """ Emulator write for PCA9632 LED.
    """
    try:
        # use self.device_name for serial device, 115200, 0.25
        with serial.Serial(device_name, baudrate=115200, timeout=0.25) as serial_device:
            serial_device.flushInput()
            serial_device.flushOutput()

            if ledstate == 'off':
                ledstate = 0x00
            elif blinkstate == 'steady' and ledstate == 'on':
                ledstate = 0x2a
            elif blinkstate == 'blink' and ledstate == 'on':
                ledstate = 0x3f

            # write ['W', self.channel] to read this device
            serial_device.write([ord('W'), channel, 0x04])
            led_bytes = [color >> 16, (color >> 8) & 0xff, color & 0xff, ledstate]
            serial_device.write(led_bytes)

            # read back result byte
            reading = serial_device.read(1)
            if reading != '1':
                raise SynseException('Invalid response received from emulator: {}'.format(reading))

            serial_device.flushInput()
            serial_device.flushOutput()

            # convert and return
            return reading
    except Exception, e:
        logger.exception(e)
        raise SynseException('Caused by {} {}'.format(type(e), e.message)), None, sys.exc_info()[2]
Beispiel #2
0
    def _read(self, command):
        """ Read the data off of a given board's device.

        Args:
            command (Command): the command issued by the Synse 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 read response.
        """
        # Get the command data out from the incoming command.
        device_id = command.data[_s_.DEVICE_ID]
        device_type_string = command.data[_s_.DEVICE_TYPE_STRING]

        try:
            # Validate device to ensure device id and type are ok.
            self._get_device_by_id(device_id, device_type_string)

            reading = self._read_sensor()

            if reading is not None:
                return Response(command=command, response_data=reading)

            # If we get here, there was no sensor device found, so we must raise.
            logger.exception(
                'No response for sensor reading for command: {}'.format(
                    command.data))
            raise SynseException('No sensor reading returned from I2C.')

        except Exception:
            logger.exception('Error reading lock')
            raise SynseException('Error reading lock (device id: {})'.format(
                device_id)), None, sys.exc_info()[2]
Beispiel #3
0
    def _asset(self, command):
        """ Asset info command for a given board and device.

        Args:
            command (Command): the command issued by the Synse 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 asset response.
        """
        # get the command data out from the incoming command
        device_id = command.data[_s_.DEVICE_ID]

        try:
            # validate that asset is supported for the device
            self._get_device_by_id(device_id, const.DEVICE_SYSTEM)
            asset_data = vapor_ipmi.get_inventory(**self._ipmi_kwargs)
            asset_data['bmc_ip'] = self.bmc_ip

            if asset_data is not None:
                return Response(command=command, response_data=asset_data)

            logger.error('No response getting asset info for {}'.format(
                command.data))
            raise SynseException(
                'No response from BMC when retrieving asset information via IPMI.'
            )

        except Exception:
            raise SynseException(
                'Error getting IPMI asset info (device id: {})'.format(
                    device_id)), None, sys.exc_info()[2]
    def _led(self, command):
        """ LED command for a given board and device.

        If an LED state is specified, this will attempt to set the LED state
        of the given device. Otherwise, it will just retrieve the currently
        configured LED state.

        Args:
            command (Command): the command issued by the Synse 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 LED response.
        """
        # get the command data from the incoming command:
        device_id = command.data[_s_.DEVICE_ID]
        led_state = command.data[_s_.LED_STATE]

        try:
            # check if the device raises an exception
            self._get_device_by_id(device_id, const.DEVICE_LED)

            links_list = [self._redfish_links['chassis']]

            if led_state is not None and led_state.lower(
            ) != _s_.LED_NO_OVERRIDE:
                if led_state.lower() in [_s_.LED_ON, _s_.LED_OFF]:
                    led_state = 'Off' if led_state.lower(
                    ) == _s_.LED_OFF else 'Lit'
                    response = vapor_redfish.set_led(
                        led_state=led_state,
                        links=links_list,
                        **self._redfish_request_kwargs)
                else:
                    logger.error(
                        'LED state unsupported for LED control operation: {}'.
                        format(led_state))
                    raise SynseException(
                        'Unsupported state change to Redfish server on LED operation.'
                    )
            else:
                response = vapor_redfish.get_led(
                    links=links_list, **self._redfish_request_kwargs)

            if response:
                return Response(command=command, response_data=response)

            logger.error('No response for LED control operation: {}'.format(
                command.data))
            raise SynseException(
                'No response from Redfish server on LED operation.')

        except ValueError as e:
            logger.error('Error with LED control: {}'.format(command.data))
            raise SynseException(
                'Error returned from Redfish server during LED operation via '
                'Redfish ({}).'.format(e))
Beispiel #5
0
def get_power_sensor(device_type, device_name, links, timeout, username, password):
    """ Get power sensor information from remote host.

    Args:
        device_type (str): 'Voltages' for a voltage device, 'PowerSupplies'
            for a power_supply device.
        device_name (str): the name of the device.
        links (list[str]): the list of links to connect to via HTTP.
        timeout (int | float): the number of seconds a GET will wait for a
            connection before timing out on the request.
        username (str): the username for basic HTTP authentication.
        password (str): the password for basic HTTP authentication.

    Returns:
        dict: power sensor information from the remote system.
    """
    response = dict()

    try:
        power_sensors = conn.get_data(
            link=links[0],
            timeout=timeout,
            username=username,
            password=password
        )
    except ValueError as e:
        logger.error('No data retrieved on GET of power schema: {}'.format(e.message))
        raise SynseException('Cannot retrieve data from power schema: {}'.format(e.message))

    try:
        power_sensors = power_sensors[device_type]
        for device in power_sensors:
            if device['Name'] == device_name:
                device_health = device['Status']['Health'].lower()
                device_status = device['Status']['State'].lower()

                response['health'] = 'ok' if device_health == 'ok' else device_health
                response['states'] = [] if response['health'] == 'ok' else [device_status]
                if device_type == 'Voltages':
                    response['voltage'] = float(device['ReadingVolts'])
        if response:
            return response
        else:
            logger.error(
                'Device information not a match to devices from GET on power schema.'
            )
            raise ValueError(
                'No device matching information from GET on power schema.'
            )
    except KeyError as e:
        logger.error(
            'Incomplete data for sensor reading from GET on power schema: '
            '{}'.format(e.message)
        )
        raise SynseException(
            'Incomplete data from power schema. Sensor information not found: '
            '{}'.format(e.message)
        )
Beispiel #6
0
def get_power(links, timeout, username, password):
    """ Get power information from the remote system.

    Args:
        links (list[str]): the list of links to connect to via HTTP.
        timeout (int | float): the number of seconds a GET will wait for a
            connection before timing out on the request.
        username (str): the username for basic HTTP authentication.
        password (str): the password for basic HTTP authentication.

    Returns:
        dict: power information from the remote system.
    """
    response = dict()
    power_data = dict()

    try:
        power_data['power'] = conn.get_data(
            link=links[1],
            timeout=timeout,
            username=username,
            password=password
        )
        power_data['systems'] = conn.get_data(
            link=links[0],
            timeout=timeout,
            username=username,
            password=password
        )
    except ValueError as e:
        unfound = ', '.join({'power', 'systems'}.difference(power_data.keys()))
        logger.error(
            'No data retrieved for {} schema(s) on GET: {}'.format(unfound, e.message)
        )
        raise SynseException(
            'Cannot retrieve data from {} schema(s): {}'.format(unfound, e.message)
        )

    try:
        response['power_status'] = power_data['systems']['PowerState'].lower()
        power_data['power'] = power_data['power']['PowerControl'][0]

        consumed_watts = power_data['power']['PowerConsumedWatts']
        power_limit = power_data['power']['PowerLimit']['LimitInWatts']

        response['over_current'] = bool(float(consumed_watts) > float(power_limit))

        health = power_data['power']['Status']['Health']
        response['power_ok'] = True if health.lower() == 'ok' else False
        response['input_power'] = float(consumed_watts)
        return response
    except KeyError as e:
        logger.error(
            'Incomplete or no data from GET on systems and power schemas: {}'.format(e.message)
        )
        raise SynseException('Cannot retrieve power data. {}'.format(e.message))
Beispiel #7
0
    def _read_sensor(self):
        """ Convenience method to return the sensor reading.

        Read the sensor by hitting the bus.

        Returns:
            dict: the temperature and humidity reading values.
        """
        with self._lock:
            if self.hardware_type == 'emulator':
                with ModbusClient(method=self.method, port=self.device_name,
                                  timeout=self.timeout) as client:

                    # read temperature
                    result = client.read_holding_registers(
                        self._register_map['temperature_register'],
                        count=1,
                        unit=self.unit)

                    if result is None:
                        raise SynseException(
                            'No response received for SHT31 temperature reading.')
                    elif isinstance(result, ExceptionResponse):
                        raise SynseException('RS485 Exception: {}'.format(result))
                    temperature = conversions.temperature_sht31_int(result.registers[0])

                    # read humidity
                    result = client.read_holding_registers(
                        self._register_map['humidity_register'],
                        count=1,
                        unit=self.unit)

                    if result is None:
                        raise SynseException(
                            'No response received for SHT31 humidity reading.')
                    elif isinstance(result, ExceptionResponse):
                        raise SynseException('RS485 Exception: {}'.format(result))
                    humidity = conversions.humidity_sht31_int(result.registers[0])

                    # Return the reading.
                    return {const.UOM_HUMIDITY: humidity, const.UOM_TEMPERATURE: temperature}

            elif self.hardware_type == 'production':
                # Production
                client = self.create_modbus_client()
                result = client.read_input_registers(self.slave_address, self.register_base, 2)
                temperature = conversions.temperature_sht31(result)
                humidity = conversions.humidity_sht31(result)

                return {const.UOM_HUMIDITY: humidity, const.UOM_TEMPERATURE: temperature}

            else:
                raise SynseException(RS485Device.HARDWARE_TYPE_UNKNOWN.format(
                    self.hardware_type))
    def _fan(self, command):
        """ Fan speed control command for a given board and device.

        Gets the fan speed for a given device. Since this is not NOT a Vapor
        Fan we can not control the fan speed, so any attempts to set the
        fan speed are met with a SynseException being raised.

        Args:
            command (Command): the command issued by the Synse 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.
        """
        device_id = command.data[_s_.DEVICE_ID]
        device_name = command.data[_s_.DEVICE_NAME]
        fan_speed = command.data[_s_.FAN_SPEED]

        try:
            if fan_speed is not None:
                raise SynseException(
                    'Setting of fan speed is not permitted for this device.')

            else:
                # check if the device raises an exception
                device = self._get_device_by_id(device_id,
                                                const.DEVICE_FAN_SPEED)
                if device['device_type'] != const.DEVICE_FAN_SPEED:
                    raise SynseException(
                        'Attempt to get fan speed for non-fan device.')

                links_list = [self._redfish_links['thermal']]

                response = vapor_redfish.get_thermal_sensor(
                    device_type='Fans',
                    device_name=device_name,
                    links=links_list,
                    **self._redfish_request_kwargs)

                if response:
                    return Response(command=command, response_data=response)

            logger.error('No response for fan control operation: {}'.format(
                command.data))
            raise SynseException(
                'No response from Redfish server on fan operation via Redfish.'
            )

        except ValueError as e:
            logger.error('Error with fan control: {}'.format(command.data))
            raise SynseException(
                'Error returned from Redfish server during fan operation via '
                'Redfish ({}).'.format(e))
    def _power(self, command):
        """ Power control command for a given board and device.

        Args:
            command (Command): the command issued by the Synse 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 power response.
        """
        # get the command data out from the incoming command
        device_id = command.data[_s_.DEVICE_ID]
        power_action = command.data[_s_.POWER_ACTION]

        try:
            # validate device supports power control
            self._get_device_by_id(device_id, const.DEVICE_POWER)

            if power_action not in [
                    _s_.PWR_ON, _s_.PWR_OFF, _s_.PWR_CYCLE, _s_.PWR_STATUS
            ]:
                raise ValueError(
                    'Invalid Redfish power action {} for board {} device {}.'.
                    format(power_action, self.board_id, device_id))
            else:
                links_list = [
                    self._redfish_links['system'], self._redfish_links['power']
                ]
                if power_action == 'status':
                    response = vapor_redfish.get_power(
                        links=links_list, **self._redfish_request_kwargs)
                else:
                    response = vapor_redfish.set_power(
                        power_action,
                        links=links_list,
                        **self._redfish_request_kwargs)

            if response:
                return Response(command=command, response_data=response)

            # if we get here there is either no device found, or response received
            logger.error('Power control attempt returned no data: {}'.format(
                command.data))
            raise SynseException(
                'No response from Redfish server for power control action.')

        except ValueError as e:
            logger.error('Error controlling Redfish power: {}'.format(
                command.data))
            raise SynseException(
                'Error returned from Redfish server in controlling power '
                'via Redfish ({}).'.format(e))
Beispiel #10
0
    def _boot_target(self, command):
        """ Boot target command for a given board and device.

        If a boot target is specified, this will attempt to set the boot device.
        Otherwise, it will just retrieve the currently configured boot device.

        Args:
            command (Command): the command issued by the Synse 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 boot target response.
        """
        # get the command data out from the incoming command
        device_id = command.data[_s_.DEVICE_ID]
        boot_target = command.data[_s_.BOOT_TARGET]

        try:
            # check if the device raises an exception
            self._get_device_by_id(device_id, const.DEVICE_SYSTEM)

            links_list = [self._redfish_links['system']]

            if boot_target in [None, 'status']:
                response = vapor_redfish.get_boot(
                    links=links_list, **self._redfish_request_kwargs)
            else:
                boot_target = _s_.BT_NO_OVERRIDE if boot_target not in [_s_.BT_PXE, _s_.BT_HDD] \
                    else boot_target

                response = vapor_redfish.set_boot(
                    target=boot_target,
                    links=links_list,
                    **self._redfish_request_kwargs)

            if response:
                return Response(command=command, response_data=response)

            logger.error('No response for boot target operation: {}'.format(
                command.data))
            raise SynseException(
                'No response from Redfish server on boot target operation via Redfish.'
            )

        except ValueError as e:
            logger.error(
                'Error getting or setting Redfish boot target: {}'.format(
                    command.data))
            raise SynseException(
                'Error returned from Redfish server during boot target operation via '
                'Redfish ({}).'.format(e))
Beispiel #11
0
    def _fan(self, command):
        """ Fan speed control command for a given board and device.

        Gets the fan speed for a given device. Since this is not NOT a Vapor
        Fan, we can not control the fan speed, so any attempts to set the
        fan speed are met with a SynseException being raised.

        Args:
            command (Command): the command issued by the Synse 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.
        """
        # get the command data out from the incoming command
        device_id = command.data[_s_.DEVICE_ID]
        device_name = command.data[_s_.DEVICE_NAME]
        fan_speed = command.data[_s_.FAN_SPEED]

        try:
            if fan_speed is not None:
                raise SynseException(
                    'Setting of fan speed is not permitted for this device.')
            else:
                device = self._get_device_by_id(device_id,
                                                const.DEVICE_FAN_SPEED)
                reading = vapor_ipmi.read_sensor(sensor_name=device_name,
                                                 **self._ipmi_kwargs)
                response = dict()
                if device['device_type'] == const.DEVICE_FAN_SPEED:
                    response[const.UOM_FAN_SPEED] = reading['sensor_reading']
                else:
                    raise SynseException(
                        'Attempt to get fan speed for non-fan device.')

                response['health'] = reading['health']
                response['states'] = reading['states']

                if response is not None:
                    return Response(command=command, response_data=response)

            logger.error('No response for fan control operation: {}'.format(
                command.data))
            raise SynseException(
                'No response from BMC on fan operation via IPMI.')

        except Exception:
            raise SynseException(
                'Error with fan control (device id: {})'.format(
                    device_id)), None, sys.exc_info()[2]
Beispiel #12
0
    def _read(self, command):
        """ Read the data off of a given board's device.

        Args:
            command (Command): the command issued by the Synse 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 read response.
        """
        # get the command data out from the incoming command
        device_id = command.data[_s_.DEVICE_ID]
        led_state = command.data.get(_s_.LED_STATE)
        color = command.data.get(_s_.LED_COLOR)
        if color is not None:
            color = int(color, 16)
        blink = command.data.get(_s_.LED_BLINK)

        # normalize the device_type_string - if it's of 'led-type', make it
        # vapor_led for board/device matching later otherwise, leave it
        # alone, which will reject erroneous reads
        device_type_string = command.data.get(_s_.DEVICE_TYPE_STRING,
                                              const.DEVICE_VAPOR_LED)

        if device_type_string in [const.DEVICE_LED, const.DEVICE_VAPOR_LED]:
            device_type_string = const.DEVICE_VAPOR_LED

        try:
            # validate device to ensure device id and type are ok
            self._get_device_by_id(device_id, device_type_string)

            reading = self._control_led(state=led_state,
                                        color=color,
                                        blink=blink)

            if reading is not None:
                return Response(command=command, response_data=reading)

            # if we get here, there was no sensor device found, so we
            # must raise
            logger.error('No response for LED status for command: {}'.format(
                command.data))
            raise SynseException('No LED status returned from I2C.')

        except Exception:
            raise SynseException(
                # NOTE: Writes go through this code path. Always did.
                'Error reading LED status (device id: {})'.format(
                    device_id)), None, sys.exc_info()[2]
Beispiel #13
0
    def _lock_function(self, command):
        """ Read or write the lock state.

        Args:
            command (Command): the command issued by the Synse 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 lock response.
        """
        # Get the command data out from the incoming command.
        device_id = command.data[_s_.DEVICE_ID]
        device_type_string = command.data[_s_.DEVICE_TYPE_STRING]
        action = command.data[_s_.ACTION]

        try:
            # Validate device to ensure device id and type are ok.
            self._get_device_by_id(device_id, device_type_string)

            if action is None or action == 'status':
                reading = self._read_sensor()

            elif action == 'lock':
                i2c_common.lock_lock(self.lock_number)
                reading = self._return_lock_status(action)

            elif action == 'unlock':
                i2c_common.lock_unlock(self.lock_number)
                reading = self._return_lock_status(action)

            elif action == 'momentary_unlock':
                i2c_common.lock_momentary_unlock(self.lock_number)
                reading = self._return_lock_status(action)

            else:
                raise SynseException(
                    'Invalid action provided for lock control.')

            return Response(
                command=command,
                response_data=reading,
            )

        except Exception:
            logger.exception('Error reading lock. Raising SynseException.')
            raise SynseException('Error reading lock (device id: {})'.format(
                device_id)), None, sys.exc_info()[2]
def read_emulator(device_name, channel):
    """ Emulator read for Max11608 ADC thermistor. This is an emulator client
    that reads two bytes from the i2c emulator and produces an integer reading.
    """
    # -- EMULATOR --
    try:
        # use self.device_name for serial device, 115200, 0.5
        with serial.Serial(device_name, baudrate=115200,
                           timeout=0.5) as serial_device:
            serial_device.flushInput()
            serial_device.flushOutput()

            # write ['R', self.channel] to read this device
            serial_device.write([ord('R'), channel, 0x00])

            # read back two bytes
            reading = serial_device.read(2)
            logger.info('<< Reading: {}'.format([hex(ord(i))
                                                 for i in reading]))
            reading = (ord(reading[0]) << 8) + ord(reading[1])

            serial_device.flushInput()
            serial_device.flushOutput()

            # convert and return
            return reading

    except Exception, e:
        logger.exception(e)
        raise SynseException('Caused by {} {}'.format(
            type(e), e.message)), None, sys.exc_info()[2]
Beispiel #15
0
    def _read_sensor(self):
        """ Convenience method to return the sensor reading from the bus.
        
        Returns:
            dict: the pressure reading value.
        """
        with self._lock:
            if self.hardware_type == 'emulator':
                # -- EMULATOR --> test-only code path
                # convert to an int from hex number string read from emulator
                sensor_int = int(
                    hexlify(read_emulator(self.device_name, self.channel)), 16)

                # value is in 16 bit 2's complement
                if sensor_int & 0x8000:
                    sensor_int = (~sensor_int + 1) & 0xFFFF
                    sensor_int = -sensor_int

                return {const.UOM_PRESSURE: sensor_int * 1.0}
            else:
                logger.debug(
                    'SDP610Pressure production _read_sensor start: {}')

                reading = i2c_common.read_differential_pressure(self.channel)
                if reading is None:
                    raise SynseException(
                        'Unable to read i2c channel {} on board id {:x}.'.
                        format(self.channel, self.board_id))

                return {const.UOM_PRESSURE: reading}
Beispiel #16
0
def get_boot(username=None, password=None, ip_address=None, port=BMC_PORT):
    """ Get boot target from remote host.

    Args:
        username (str): username to connect to BMC with.
        password (str): password to connect to BMC with.
        ip_address (str): BMC IP address.
        port (int): BMC port.

    Returns:
        dict: boot target as observed, or IpmiException from pyghmi.
    """
    response = dict()
    with IpmiCommand(ip_address=ip_address,
                     username=username,
                     password=password,
                     port=port) as ipmicmd:
        result = ipmicmd.get_bootdev()
        if 'error' in result:
            raise SynseException(
                'Error retrieving boot device from IPMI BMC {} : {}'.format(
                    ip_address, result['error']))

        # FIXME (etd) - here, if bootdev doesn't exist, we use 'unknown'. in the dict `get`
        # in the following line, there is no record for unknown, so it will default to the
        # value of `None` -- is this desired?
        bootdev = result.get('bootdev', 'unknown')
        bootdev = dict(network='pxe', hd='hdd',
                       default='no_override').get(bootdev)
        response['target'] = bootdev
        return response
Beispiel #17
0
def sensors(username=None, password=None, ip_address=None, port=BMC_PORT):
    """ Get a list of sensors from remote system.

    Args:
        username (str): the username to use to connect to the remote BMC.
        password (str): the password to use to connect to the remote BMC.
        ip_address (str): the IP address of the BMC.
        port (int): BMC port.

    Returns:
        list[dict]: sensor number, id string, and type for each sensor available.
    """
    with IpmiCommand(ip_address=ip_address,
                     username=username,
                     password=password,
                     port=port) as ipmicmd:
        sdr = ipmicmd.init_sdr()
        if sdr is None:
            raise SynseException(
                'Error initializing SDR from IPMI BMC {}'.format(ip_address))
        response = [{
            'sensor_number': sensor.sensor_number,
            'id_string': sensor.name,
            'sensor_type': sensor.sensor_type
        } for sensor in sdr.sensors.values()]
        return response
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 _read_sensor(self):
        """ Internal method for reading data off of the device.

        Returns:
            dict: the thermistor reading value.
        """
        with self._lock:
            if self.hardware_type == 'emulator':
                # -- EMULATOR --> test-only code path
                raw = read_emulator(self.device_name, self.channel)
                # raw is an int like 0.
                # Conversion takes packed bytes.
                # Get packed bytes for the conversion.
                packed = struct.pack('>H', raw)
                return {
                    const.UOM_TEMPERATURE:
                    conversions.thermistor_max11608_adc(packed)
                }

            elif self.hardware_type == 'production':
                # Channel is zero based in the synse config.
                # Read channel + 1 thermistors and return the last one read in the reading.
                readings = i2c_common.read_thermistors(
                    self.channel + 1,
                    type(self)._instance_name)
                return {const.UOM_TEMPERATURE: readings[self.channel]}

            else:
                raise SynseException('Unknown hardware type {}.'.format(
                    self.hardware_type))
Beispiel #20
0
def set_led(led_state, links, timeout, username, password):
    """ Turn the remote system LED on or off.

    Args:
        led_state (str): the state to set the led to on the remote device.
        links (list[str]): the list of links to connect to via HTTP.
        timeout (int | float): the number of seconds a PATCH will wait for
            a connection before timing out on the request.
        username (str): the username for basic HTTP authentication.
        password (str): the password for basic HTTP authentication.

    Returns:
        dict: LED state as set.
    """
    _payload = {'IndicatorLED': led_state}

    try:
        conn.patch_data(
            link=links[0],
            payload=_payload,
            timeout=timeout,
            username=username,
            password=password,
        )
        response = get_led(links=links, timeout=timeout, username=username, password=password)
        return response
    except ValueError as e:
        logger.error(
            'LED state not set on PATCH or response not returned on GET: {}'.format(e.message)
        )
        raise SynseException(
            'LED state cannot be set. POST error or GET error: {}'.format(e.message)
        )
Beispiel #21
0
def read_emulator(device_name, channel):
    """ Emulator read for SDP610 pressure.
    """
    # -- EMULATOR --
    try:
        # use self.device_name for serial device, 115200, 0.25
        with serial.Serial(device_name, baudrate=115200,
                           timeout=0.5) as serial_device:
            serial_device.flushInput()
            serial_device.flushOutput()

            # write ['R', self.channel] to read this device
            serial_device.write([ord('R'), channel, 0x00])

            # read back two bytes (CRC omitted for emulator)
            reading = serial_device.read(2)

            serial_device.flushInput()
            serial_device.flushOutput()

            # convert and return
            return reading

    except Exception, e:
        logger.exception(e)
        raise SynseException('Caused by {} {}'.format(
            type(e), e.message)), None, sys.exc_info()[2]
def get_data(link, timeout, username=None, password=None):
    """ Gets the JSON data from the Redfish server via the link specified.

    Args:
        link (str): the link to which information is requested.
        timeout (int | float): the number of seconds a GET will wait for a
            connection before timing out on the request.
        username (str): the username for basic authentication.
        password (str): the password for basic authentication.

    Returns:
        dict: a representation of the JSON data from the Redfish server.
    """
    try:
        if username is not None and password is not None:
            r = requests.get(link,
                             timeout=timeout,
                             auth=HTTPBasicAuth(username, password))
        else:
            r = requests.get(link, timeout=timeout)
    except requests.exceptions.ConnectionError as e:
        raise SynseException(
            'Unable to GET link {} due to ConnectionError: {}'.format(
                link, e.message))

    if r.status_code != 200:
        logger.error('Unexpected status code for GET method: {}'.format(
            r.status_code))
        raise ValueError('Unable to GET link {}. Status code: {}'.format(
            link, r.status_code))
    else:
        return r.json()
Beispiel #23
0
def get_dcmi_management_controller_id(username=None,
                                      password=None,
                                      ip_address=None,
                                      port=BMC_PORT):
    """ Get DCMI management controller ID from remote BMC.

    Args:
        username (str): username to connect to BMC with.
        password (str): password to connect to BMC with.
        ip_address (str): BMC IP address.
        port (int): BMC port.

    Returns:
        str: the management controller ID.

    Raises:
        SynseException: IPMI command failed or provided invalid response.
    """
    id_string = ''

    # read the mgmt controller ID out in blocks of 16 bytes, up to the limit of 64 bytes
    with IpmiCommand(ip_address=ip_address,
                     username=username,
                     password=password,
                     port=port) as ipmicmd:
        for x in range(0, 4):
            result = ipmicmd.raw_command(netfn=0x2c,
                                         command=0x01,
                                         data=(0xdc, x * 0x10))
            if 'error' in result:
                raise SynseException(
                    'Error executing get DCMI controller ID command on {} : {}'
                    .format(ip_address, result['error']))

            # byte 0 should always be 0xdc
            if result['data'][0] != 0xdc:
                raise SynseException(
                    'Error in response to get DCMI controller ID command on {}: Invalid '
                    'first byte.'.format(ip_address))

            # byte 1 should be the string length - ignore as remaining bytes are 0x00 (null)

            # tack on the remaining characters to the id string
            id_string.join([chr(c) for c in result['data'][2:]])

    return id_string
Beispiel #24
0
    def _control_led(self, state=None, blink=None, color=None):
        """ Internal method for LED control.

        Args:
            state (str): the LED state. can be either 'on' or 'off'.
            blink (str): the LED blink state. can be either 'steady' or 'blink'.
            color (str (emulator) str or int (production)):
                The 3 byte RGB color to set the LED to.

        Returns:
            dict: a dictionary containing the LED state, which includes its
                color, state, and blink state.
        """
        logger.debug('_control_led(): state {}, blink {}, color {}.'.format(
            state, blink, color))
        with self._lock:
            if self.hardware_type == 'emulator':
                # -- EMULATOR --> test-only code path
                if state is not None:
                    red = color >> 16
                    green = (color >> 8) & 0xff
                    blue = color & 0xff
                    write_emulator(self.device_name, self.channel,
                                   (red << 16) | (green << 8) | blue, state,
                                   blink)

                reading = read_emulator(self.device_name, self.channel)
                return {
                    _s_.LED_COLOR: format(reading['color'], '06x'),
                    _s_.LED_STATE: reading['state'],
                    _s_.LED_BLINK_STATE: reading['blink']
                }
            elif self.hardware_type == 'production':
                if state is None and blink is None and color is None:
                    return self._read_sensor()
                elif state is not None:
                    return self._write_sensor(state, color, blink)
                else:
                    logger.error('_control_led() Not read or write.')
                    raise SynseException(
                        'Unexpected arguments state: {}, color: {}, blink {}.'.
                        format(state, color, blink))
            else:
                raise SynseException('Unknown hardware_type {}.'.format(
                    self.hardware_type))
Beispiel #25
0
    def _read(self, command):
        """ Read the data off of a given board's device.

        Args:
            command (Command): the command issued by the Synse 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 read response.
        """
        # get the command data out from the incoming command
        device_id = command.data[_s_.DEVICE_ID]
        device_type_string = command.data[_s_.DEVICE_TYPE_STRING]

        if device_type_string not in [
                const.DEVICE_VAPOR_FAN, const.DEVICE_FAN_SPEED
        ]:
            # this command is not for us
            raise SynseException('Incorrect device type "{}" for fan.'.format(
                device_type_string))

        # FIXME: override because main_blueprint doesn't distinguish between
        # 'fan_speed' and 'vapor_fan'
        device_type_string = const.DEVICE_VAPOR_FAN

        try:
            # validate device to ensure device id and type are ok
            self._get_device_by_id(device_id, device_type_string)

            reading = self._fan_control(action='status')

            if reading is not None:
                return Response(command=command, response_data=reading)

            # if we get here, there was no vapor_fan device found, so we must raise
            logger.error('No response for fan control for command: {}'.format(
                command.data))
            raise SynseException(
                'No fan control response returned from RS485.')

        except Exception:
            raise SynseException(
                'Error controlling fan controller (device id: {})'.format(
                    device_id)), None, sys.exc_info()[2]
Beispiel #26
0
    def _led(self, command):
        """ LED command for a given board and device.

        If an LED state is specified, this will attempt to set the LED state
        of the given device. Otherwise, it will just retrieve the currently
        configured LED state.

        Args:
            command (Command): the command issued by the Synse 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 LED response.
        """
        # get the command data out from the incoming command
        device_id = command.data[_s_.DEVICE_ID]
        led_state = command.data[_s_.LED_STATE]

        try:
            if led_state is not None:
                self._get_device_by_id(device_id, const.DEVICE_LED)
                led_state = 0 if led_state.lower() == _s_.LED_OFF else 1
                led_response = vapor_ipmi.set_identify(led_state=led_state,
                                                       **self._ipmi_kwargs)
                led_response['led_state'] = _s_.LED_OFF if led_response['led_state'] == 0 \
                    else _s_.LED_ON
            else:
                self._get_device_by_id(device_id, const.DEVICE_LED)
                led_response = vapor_ipmi.get_identify(**self._ipmi_kwargs)

            if led_response is not None:
                return Response(command=command, response_data=led_response)

            logger.error('No response for LED control operation: {}'.format(
                command.data))
            raise SynseException(
                'No response from BMC on LED operation via IPMI.')

        except Exception:
            raise SynseException(
                'Error with LED control (device id: {})'.format(
                    device_id)), None, sys.exc_info()[2]
Beispiel #27
0
 def _set_hardware_type(self, hardware_type):
     """Known hardware types are emulator and production. Check that the
     parameter is known and set self.hardware_type.
     :param hardware_type: The hardware_type the caller would like to set.
     :raises SynseException: The given hardware_type is not known."""
     known = ['emulator', 'production']
     if hardware_type not in known:
         raise SynseException(
             RS485Device.HARDWARE_TYPE_UNKNOWN.format(hardware_type))
     self.hardware_type = hardware_type
Beispiel #28
0
 def _check_fan_speed_setting(self, speed_rpm):
     """Ensure that the caller's speed_rpm setting is valid.
     :param speed_rpm: The speed_rpm setting from the caller.
     :raises: SynseException on failure."""
     if self.hardware_type == 'emulator':
         if speed_rpm < 0:
             raise SynseException(
                 'Invalid speed setting {} for fan control.'.format(
                     speed_rpm))
     elif self.hardware_type == 'production':
         if speed_rpm != 0:
             if not self.min_nonzero_rpm <= speed_rpm <= self.max_rpm:
                 raise SynseException(
                     'Invalid speed setting {} for fan control - '
                     'must be zero or between {} and {}'.format(
                         speed_rpm, self.min_nonzero_rpm, self.max_rpm))
     else:
         raise SynseException('Unknown hardware type {}.',
                              self.hardware_type)
Beispiel #29
0
    def _read(self, command):
        """ Read the data off of a given board's device.

        Args:
            command (Command): the command issued by the Synse 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 read response.
        """
        # get the command data out from the incoming command
        device_id = command.data[_s_.DEVICE_ID]
        device_type_string = command.data[_s_.DEVICE_TYPE_STRING]

        try:
            device = self._get_device_by_id(device_id, device_type_string)

            reading = vapor_ipmi.read_sensor(sensor_name=device['device_info'],
                                             **self._ipmi_kwargs)
            response = dict()

            uom = get_measure_for_device_type(device['device_type'])
            if uom is not None:
                response[uom] = reading['sensor_reading']

            response['health'] = reading['health']
            response['states'] = reading['states']

            if response is not None:
                return Response(command=command, response_data=response)

            # if we get here, there was no sensor device found, so we must raise
            logger.error(
                'No response for sensor reading for command: {}'.format(
                    command.data))
            raise SynseException('No sensor reading returned from BMC.')

        except Exception:
            raise SynseException(
                'Error reading IPMI sensor (device id: {})'.format(
                    device_id)), None, sys.exc_info()[2]
Beispiel #30
0
def get_inventory(username=None,
                  password=None,
                  ip_address=None,
                  port=BMC_PORT):
    """ Get inventory information from the FRU of the remote system.

    Args:
        username (str): the username to connect to BMC with.
        password (str): the password to connect to BMC with.
        ip_address (str): the IP address of the BMC.
        port (int): BMC port.

    Returns:
        dict: inventory information from the remote system.
    """
    response = dict()
    with IpmiCommand(ip_address=ip_address,
                     username=username,
                     password=password,
                     port=port) as ipmicmd:
        result = ipmicmd.get_inventory_of_component('System')
        if 'error' in result:
            raise SynseException(
                'Error retrieving System inventory from IPMI BMC {} : {}'.
                format(ip_address, result['error']))

        response['chassis_info'] = dict()
        response['chassis_info']['chassis_type'] = result.get(
            'Chassis type', '')
        response['chassis_info']['part_number'] = result.get(
            'Chassis part number', '')
        response['chassis_info']['serial_number'] = result.get(
            'Chassis serial number', '')
        response['board_info'] = dict()
        response['board_info']['manufacturer'] = result.get(
            'Board manufacturer', '')
        response['board_info']['part_number'] = result.get(
            'Board part number', '')
        response['board_info']['product_name'] = result.get(
            'Board product name', '')
        response['board_info']['serial_number'] = result.get(
            'Board serial number', '')
        response['product_info'] = dict()
        response['product_info']['asset_tag'] = result.get('Asset Number', '')
        response['product_info']['part_number'] = result.get('Model', '')
        response['product_info']['manufacturer'] = result.get(
            'Manufacturer', '')
        response['product_info']['product_name'] = result.get(
            'Product name', '')
        response['product_info']['serial_number'] = result.get(
            'Serial Number', '')
        response['product_info']['version'] = result.get(
            'Hardware Version', '')
        return response