Beispiel #1
0
    def _test_inspect_hardware_props(
            self, gpu_ids, fpga_ids, existed_capabilities,
            inspected_capabilities, expected_capabilities, existed_traits,
            expected_traits, get_irmc_report_mock, scci_mock,
            _get_mac_addresses_mock, trait_mock):
        capabilities_props = set(irmc_inspect.CAPABILITIES_PROPERTIES)

        # if gpu_ids = [], pci_gpu_devices will not be inspected
        if len(gpu_ids) == 0:
            capabilities_props.remove('pci_gpu_devices')

        # if fpga_ids = [], cpu_fpga will not be inspected
        if fpga_ids is None or len(fpga_ids) == 0:
            capabilities_props.remove('cpu_fpga')

        self.config(gpu_ids=gpu_ids, group='irmc')
        self.config(fpga_ids=fpga_ids, group='irmc')
        kwargs = {'sleep_flag': False}

        inspected_props = {
            'memory_mb': '1024',
            'local_gb': 10,
            'cpus': 2,
            'cpu_arch': 'x86_64'
        }

        inspected_macs = ['aa:aa:aa:aa:aa:aa', 'bb:bb:bb:bb:bb:bb']
        report = 'fake_report'

        get_irmc_report_mock.return_value = report
        scci_mock.get_essential_properties.return_value = inspected_props
        scci_mock.get_capabilities_properties.return_value = \
            inspected_capabilities
        _get_mac_addresses_mock.return_value = inspected_macs
        trait_mock.return_value = existed_traits

        with task_manager.acquire(self.context, self.node.uuid,
                                  shared=True) as task:
            task.node.properties[u'capabilities'] =\
                ",".join('%(k)s:%(v)s' % {'k': k, 'v': v}
                         for k, v in existed_capabilities.items())
            result = irmc_inspect._inspect_hardware(task.node, existed_traits,
                                                    **kwargs)
            get_irmc_report_mock.assert_called_once_with(task.node)
            scci_mock.get_essential_properties.assert_called_once_with(
                report, irmc_inspect.IRMCInspect.ESSENTIAL_PROPERTIES)
            scci_mock.get_capabilities_properties.assert_called_once_with(
                mock.ANY,
                capabilities_props,
                gpu_ids,
                fpga_ids=fpga_ids,
                **kwargs)
            expected_capabilities = utils.get_updated_capabilities(
                '', expected_capabilities)

            set1 = set(expected_capabilities.split(','))
            set2 = set(result[0]['capabilities'].split(','))
            self.assertEqual(set1, set2)
            self.assertEqual(expected_traits, result[2])
Beispiel #2
0
 def test_get_updated_capabilities_replace_to_existing_capabilities(self):
     new_capabilities = {"BootMode": "bios"}
     expected_capabilities = "BootMode:bios"
     cap_returned = utils.get_updated_capabilities("BootMode:uefi", new_capabilities)
     set1 = set(expected_capabilities.split(","))
     set2 = set(cap_returned.split(","))
     self.assertEqual(set1, set2)
     self.assertIsInstance(cap_returned, str)
Beispiel #3
0
 def test_get_updated_capabilities_multiple_keys(self):
     capabilities = {"ilo_firmware_version": "xyz", "foo": "bar", "somekey": "value"}
     cap_string = "ilo_firmware_version:xyz,foo:bar,somekey:value"
     cap_returned = utils.get_updated_capabilities(None, capabilities)
     set1 = set(cap_string.split(","))
     set2 = set(cap_returned.split(","))
     self.assertEqual(set1, set2)
     self.assertIsInstance(cap_returned, str)
Beispiel #4
0
def _inspect_hardware(node, **kwargs):
    """Inspect the node and get hardware information.

    :param node: node object.
    :param kwargs: the dictionary of additional parameters.
    :raises: HardwareInspectionFailure, if unable to get essential
             hardware properties.
    :returns: a pair of dictionary and list, the dictionary contains
              keys as in IRMCInspect.ESSENTIAL_PROPERTIES and its inspected
              values, the list contains mac addresses.
    """
    capabilities_props = set(CAPABILITIES_PROPERTIES)

    # Remove all capabilities item which will be inspected in the existing
    # capabilities of node
    if 'capabilities' in node.properties:
        existing_cap = node.properties['capabilities'].split(',')
        for item in capabilities_props:
            for prop in existing_cap:
                if item == prop.split(':')[0]:
                    existing_cap.remove(prop)
        node.properties['capabilities'] = ",".join(existing_cap)

    # get gpu_ids in ironic configuration
    values = [gpu_id.lower() for gpu_id in CONF.irmc.gpu_ids]

    # if gpu_ids = [], pci_gpu_devices will not be inspected
    if len(values) == 0:
        capabilities_props.remove('pci_gpu_devices')

    try:
        report = irmc_common.get_irmc_report(node)
        props = scci.get_essential_properties(report,
                                              IRMCInspect.ESSENTIAL_PROPERTIES)
        d_info = irmc_common.parse_driver_info(node)
        capabilities = scci.get_capabilities_properties(
            d_info, capabilities_props, values, **kwargs)
        if capabilities:
            if capabilities.get('pci_gpu_devices') == 0:
                capabilities.pop('pci_gpu_devices')
            if capabilities.get('trusted_boot') is False:
                capabilities.pop('trusted_boot')
            capabilities = utils.get_updated_capabilities(
                node.properties.get('capabilities'), capabilities)
            if capabilities:
                props['capabilities'] = capabilities
        macs = _get_mac_addresses(node)
    except (scci.SCCIInvalidInputError, scci.SCCIClientError,
            exception.SNMPFailure) as e:
        error = (_("Inspection failed for node %(node_id)s "
                   "with the following error: %(error)s") % {
                       'node_id': node.uuid,
                       'error': e
                   })
        raise exception.HardwareInspectionFailure(error=error)

    return (props, macs)
Beispiel #5
0
 def test_get_updated_capabilities_replace_to_existing_capabilities(self):
     new_capabilities = {'BootMode': 'bios'}
     expected_capabilities = 'BootMode:bios'
     cap_returned = utils.get_updated_capabilities('BootMode:uefi',
                                                   new_capabilities)
     set1 = set(expected_capabilities.split(','))
     set2 = set(cap_returned.split(','))
     self.assertEqual(set1, set2)
     self.assertIsInstance(cap_returned, str)
Beispiel #6
0
 def test_get_updated_capabilities_multiple_keys(self):
     capabilities = {'ilo_firmware_version': 'xyz',
                     'foo': 'bar', 'somekey': 'value'}
     cap_string = 'ilo_firmware_version:xyz,foo:bar,somekey:value'
     cap_returned = utils.get_updated_capabilities(None, capabilities)
     set1 = set(cap_string.split(','))
     set2 = set(cap_returned.split(','))
     self.assertEqual(set1, set2)
     self.assertIsInstance(cap_returned, str)
Beispiel #7
0
 def test_get_updated_capabilities_multiple_keys(self):
     capabilities = {'ilo_firmware_version': 'xyz',
                     'foo': 'bar', 'somekey': 'value'}
     cap_string = 'ilo_firmware_version:xyz,foo:bar,somekey:value'
     cap_returned = utils.get_updated_capabilities(None, capabilities)
     set1 = set(cap_string.split(','))
     set2 = set(cap_returned.split(','))
     self.assertEqual(set1, set2)
     self.assertIsInstance(cap_returned, str)
Beispiel #8
0
 def test_get_updated_capabilities_replace_to_existing_capabilities(self):
     new_capabilities = {'BootMode': 'bios'}
     expected_capabilities = 'BootMode:bios'
     cap_returned = utils.get_updated_capabilities('BootMode:uefi',
                                                   new_capabilities)
     set1 = set(expected_capabilities.split(','))
     set2 = set(cap_returned.split(','))
     self.assertEqual(set1, set2)
     self.assertIsInstance(cap_returned, str)
Beispiel #9
0
    def test__inspect_hardware(self, get_irmc_report_mock, scci_mock,
                               _get_mac_addresses_mock):
        # Set config flags
        gpu_ids = ['0x1000/0x0079', '0x2100/0x0080']
        cpu_fpgas = ['0x1000/0x0179', '0x2100/0x0180']
        self.config(gpu_ids=gpu_ids, group='irmc')
        self.config(fpga_ids=cpu_fpgas, group='irmc')
        kwargs = {'sleep_flag': False}

        inspected_props = {
            'memory_mb': '1024',
            'local_gb': 10,
            'cpus': 2,
            'cpu_arch': 'x86_64'
        }
        inspected_capabilities = {
            'trusted_boot': False,
            'irmc_firmware_version': 'iRMC S4-7.82F',
            'server_model': 'TX2540M1F5',
            'rom_firmware_version': 'V4.6.5.4 R1.15.0 for D3099-B1x',
            'pci_gpu_devices': 1,
            'cpu_fpga': 1
        }
        new_traits = ['CUSTOM_CPU_FPGA']
        existing_traits = []

        inspected_macs = ['aa:aa:aa:aa:aa:aa', 'bb:bb:bb:bb:bb:bb']
        report = 'fake_report'
        get_irmc_report_mock.return_value = report
        scci_mock.get_essential_properties.return_value = inspected_props
        scci_mock.get_capabilities_properties.return_value = (
            inspected_capabilities)
        _get_mac_addresses_mock.return_value = inspected_macs
        with task_manager.acquire(self.context, self.node.uuid,
                                  shared=True) as task:
            result = irmc_inspect._inspect_hardware(task.node, existing_traits,
                                                    **kwargs)
            get_irmc_report_mock.assert_called_once_with(task.node)
            scci_mock.get_essential_properties.assert_called_once_with(
                report, irmc_inspect.IRMCInspect.ESSENTIAL_PROPERTIES)
            scci_mock.get_capabilities_properties.assert_called_once_with(
                mock.ANY,
                irmc_inspect.CAPABILITIES_PROPERTIES,
                gpu_ids,
                fpga_ids=cpu_fpgas,
                **kwargs)

            expected_props = dict(inspected_props)
            inspected_capabilities = utils.get_updated_capabilities(
                '', inspected_capabilities)
            expected_props['capabilities'] = inspected_capabilities
            self.assertEqual((expected_props, inspected_macs, new_traits),
                             result)
Beispiel #10
0
    def test__inspect_hardware(
            self, get_irmc_report_mock, scci_mock, _get_mac_addresses_mock):
        # Set config flags
        gpu_ids = ['0x1000/0x0079', '0x2100/0x0080']
        cpu_fpgas = ['0x1000/0x0179', '0x2100/0x0180']
        self.config(gpu_ids=gpu_ids, group='irmc')
        self.config(fpga_ids=cpu_fpgas, group='irmc')
        kwargs = {'sleep_flag': False}

        inspected_props = {
            'memory_mb': '1024',
            'local_gb': 10,
            'cpus': 2,
            'cpu_arch': 'x86_64'}
        inspected_capabilities = {
            'trusted_boot': False,
            'irmc_firmware_version': 'iRMC S4-7.82F',
            'server_model': 'TX2540M1F5',
            'rom_firmware_version': 'V4.6.5.4 R1.15.0 for D3099-B1x',
            'pci_gpu_devices': 1,
            'cpu_fpga': 1}
        new_traits = ['CUSTOM_CPU_FPGA']
        existing_traits = []

        inspected_macs = ['aa:aa:aa:aa:aa:aa', 'bb:bb:bb:bb:bb:bb']
        report = 'fake_report'
        get_irmc_report_mock.return_value = report
        scci_mock.get_essential_properties.return_value = inspected_props
        scci_mock.get_capabilities_properties.return_value = (
            inspected_capabilities)
        _get_mac_addresses_mock.return_value = inspected_macs
        with task_manager.acquire(self.context, self.node.uuid,
                                  shared=True) as task:
            result = irmc_inspect._inspect_hardware(task.node,
                                                    existing_traits,
                                                    **kwargs)
            get_irmc_report_mock.assert_called_once_with(task.node)
            scci_mock.get_essential_properties.assert_called_once_with(
                report, irmc_inspect.IRMCInspect.ESSENTIAL_PROPERTIES)
            scci_mock.get_capabilities_properties.assert_called_once_with(
                mock.ANY, irmc_inspect.CAPABILITIES_PROPERTIES,
                gpu_ids, fpga_ids=cpu_fpgas, **kwargs)

            expected_props = dict(inspected_props)
            inspected_capabilities = utils.get_updated_capabilities(
                '', inspected_capabilities)
            expected_props['capabilities'] = inspected_capabilities
            self.assertEqual((expected_props, inspected_macs, new_traits),
                             result)
Beispiel #11
0
def update_raid_info(node, raid_config):
    """Update the node's information based on the RAID config.

    This method updates the node's information to make use of the configured
    RAID for scheduling purposes (through properties['capabilities'] and
    properties['local_gb']) and deploying purposes (using
    properties['root_device']).

    :param node: a node object
    :param raid_config: The dictionary containing the current RAID
        configuration.
    :raises: InvalidParameterValue, if 'raid_config' has more than
        one root volume or if node.properties['capabilities'] is malformed.
    """
    current = raid_config.copy()
    current['last_updated'] = str(datetime.datetime.utcnow())
    node.raid_config = current
    node.target_raid_config = None

    # Current RAID configuration can have 0 or 1 root volumes. If there
    # are > 1 root volumes, then it's invalid.  We check for this condition
    # while accepting target RAID configuration, but this check is just in
    # place, if some drivers pass > 1 root volumes to this method.
    root_logical_disk = _check_and_return_root_volumes(raid_config)
    if root_logical_disk:
        # Update local_gb and root_device_hint
        properties = node.properties
        properties['local_gb'] = root_logical_disk['size_gb']
        try:
            properties['root_device'] = (
                root_logical_disk['root_device_hint'])
        except KeyError:
            pass
        properties['capabilities'] = utils.get_updated_capabilities(
            properties.get('capabilities', ''),
            {'raid_level': root_logical_disk['raid_level']})
        node.properties = properties

    node.save()
Beispiel #12
0
def update_raid_info(node, raid_config):
    """Update the node's information based on the RAID config.

    This method updates the node's information to make use of the configured
    RAID for scheduling purposes (through properties['capabilities'] and
    properties['local_gb']) and deploying purposes (using
    properties['root_device']).

    :param node: a node object
    :param raid_config: The dictionary containing the current RAID
        configuration.
    :raises: InvalidParameterValue, if 'raid_config' has more than
        one root volume or if node.properties['capabilities'] is malformed.
    """
    current = raid_config.copy()
    current['last_updated'] = str(datetime.datetime.utcnow())
    node.raid_config = current
    node.target_raid_config = None

    # Current RAID configuration can have 0 or 1 root volumes. If there
    # are > 1 root volumes, then it's invalid.  We check for this condition
    # while accepting target RAID configuration, but this check is just in
    # place, if some drivers pass > 1 root volumes to this method.
    root_logical_disk = _check_and_return_root_volumes(raid_config)
    if root_logical_disk:
        # Update local_gb and root_device_hint
        properties = node.properties
        properties['local_gb'] = root_logical_disk['size_gb']
        try:
            properties['root_device'] = (root_logical_disk['root_device_hint'])
        except KeyError:
            pass
        properties['capabilities'] = utils.get_updated_capabilities(
            properties.get('capabilities', ''),
            {'raid_level': root_logical_disk['raid_level']})
        node.properties = properties

    node.save()
Beispiel #13
0
 def test_get_updated_capabilities(self):
     capabilities = {'ilo_firmware_version': 'xyz'}
     cap_string = 'ilo_firmware_version:xyz'
     cap_returned = utils.get_updated_capabilities(None, capabilities)
     self.assertEqual(cap_string, cap_returned)
     self.assertIsInstance(cap_returned, str)
Beispiel #14
0
def _inspect_hardware(node, existing_traits=None, **kwargs):
    """Inspect the node and get hardware information.

    :param node: node object.
    :param existing_traits: existing traits list.
    :param kwargs: the dictionary of additional parameters.
    :raises: HardwareInspectionFailure, if unable to get essential
             hardware properties.
    :returns: a pair of dictionary and list, the dictionary contains
              keys as in IRMCInspect.ESSENTIAL_PROPERTIES and its inspected
              values, the list contains mac addresses.
    """
    capabilities_props = set(CAPABILITIES_PROPERTIES)
    new_traits = list(existing_traits) if existing_traits else []

    # Remove all capabilities item which will be inspected in the existing
    # capabilities of node
    if 'capabilities' in node.properties:
        existing_cap = node.properties['capabilities'].split(',')
        for item in capabilities_props:
            for prop in existing_cap:
                if item == prop.split(':')[0]:
                    existing_cap.remove(prop)
        node.properties['capabilities'] = ",".join(existing_cap)

    # get gpu_ids, fpga_ids in ironic configuration
    gpu_ids = [gpu_id.lower() for gpu_id in CONF.irmc.gpu_ids]
    fpga_ids = [fpga_id.lower() for fpga_id in CONF.irmc.fpga_ids]

    # if gpu_ids = [], pci_gpu_devices will not be inspected
    if len(gpu_ids) == 0:
        capabilities_props.remove('pci_gpu_devices')

    # if fpga_ids = [], cpu_fpga will not be inspected
    if len(fpga_ids) == 0:
        capabilities_props.remove('cpu_fpga')

    try:
        report = irmc_common.get_irmc_report(node)
        props = scci.get_essential_properties(
            report, IRMCInspect.ESSENTIAL_PROPERTIES)
        d_info = irmc_common.parse_driver_info(node)
        capabilities = scci.get_capabilities_properties(
            d_info,
            capabilities_props,
            gpu_ids,
            fpga_ids=fpga_ids,
            **kwargs)
        if capabilities:
            if capabilities.get('pci_gpu_devices') == 0:
                capabilities.pop('pci_gpu_devices')

            cpu_fpga = capabilities.pop('cpu_fpga', 0)
            if cpu_fpga == 0 and 'CUSTOM_CPU_FPGA' in new_traits:
                new_traits.remove('CUSTOM_CPU_FPGA')
            elif cpu_fpga != 0 and 'CUSTOM_CPU_FPGA' not in new_traits:
                new_traits.append('CUSTOM_CPU_FPGA')

            if capabilities.get('trusted_boot') is False:
                capabilities.pop('trusted_boot')
            capabilities = utils.get_updated_capabilities(
                node.properties.get('capabilities'), capabilities)
            if capabilities:
                props['capabilities'] = capabilities

        macs = _get_mac_addresses(node)
    except (scci.SCCIInvalidInputError,
            scci.SCCIClientError,
            exception.SNMPFailure) as e:
        error = (_("Inspection failed for node %(node_id)s "
                   "with the following error: %(error)s") %
                 {'node_id': node.uuid, 'error': e})
        raise exception.HardwareInspectionFailure(error=error)

    return props, macs, new_traits
Beispiel #15
0
    def inspect_hardware(self, task):
        """Inspect hardware to get the hardware properties.

        Inspects hardware to get the essential properties.
        It fails if any of the essential properties
        are not received from the node.

        :param task: a TaskManager instance.
        :raises: HardwareInspectionFailure if essential properties
                 could not be retrieved successfully.
        :returns: The resulting state of inspection.

        """
        system = redfish_utils.get_system(task.node)

        # get the essential properties and update the node properties
        # with it.
        inspected_properties = task.node.properties

        if system.memory_summary and system.memory_summary.size_gib:
            inspected_properties['memory_mb'] = str(
                system.memory_summary.size_gib * units.Ki)

        if system.processors and system.processors.summary:
            cpus, arch = system.processors.summary
            if cpus:
                inspected_properties['cpus'] = cpus

            if arch:
                try:
                    inspected_properties['cpu_arch'] = CPU_ARCH_MAP[arch]

                except KeyError:
                    LOG.warning(
                        "Unknown CPU arch %(arch)s discovered "
                        "for node %(node)s", {
                            'node': task.node.uuid,
                            'arch': arch
                        })

        # TODO(etingof): should we respect root device hints here?
        local_gb = self._detect_local_gb(task, system)

        if local_gb:
            inspected_properties['local_gb'] = str(local_gb)
        else:
            LOG.warning(
                "Could not provide a valid storage size configured "
                "for node %(node)s. Assuming this is a disk-less node",
                {'node': task.node.uuid})
            inspected_properties['local_gb'] = '0'

        if system.boot.mode:
            if not drivers_utils.get_node_capability(task.node, 'boot_mode'):
                capabilities = utils.get_updated_capabilities(
                    inspected_properties.get('capabilities', ''),
                    {'boot_mode': BOOT_MODE_MAP[system.boot.mode]})

                inspected_properties['capabilities'] = capabilities

        valid_keys = self.ESSENTIAL_PROPERTIES
        missing_keys = valid_keys - set(inspected_properties)
        if missing_keys:
            error = (_('Failed to discover the following properties: '
                       '%(missing_keys)s on node %(node)s'), {
                           'missing_keys': ', '.join(missing_keys),
                           'node': task.node.uuid
                       })
            raise exception.HardwareInspectionFailure(error=error)

        task.node.properties = inspected_properties
        task.node.save()

        LOG.debug(
            "Node properties for %(node)s are updated as "
            "%(properties)s", {
                'properties': inspected_properties,
                'node': task.node.uuid
            })

        self._create_ports(task, system)

        return states.MANAGEABLE
Beispiel #16
0
    def inspect_hardware(self, task):
        """Inspect hardware to get the hardware properties.

        Inspects hardware to get the essential and additional hardware
        properties. It fails if any of the essential properties
        are not received from the node.  It doesn't fail if node fails
        to return any capabilities as the capabilities differ from hardware
        to hardware mostly.

        :param task: a TaskManager instance.
        :raises: HardwareInspectionFailure if essential properties
                 could not be retrieved successfully.
        :raises: IloOperationError if system fails to get power state.
        :returns: The resulting state of inspection.

        """
        power_turned_on = False
        ilo_object = ilo_common.get_ilo_object(task.node)
        try:
            state = task.driver.power.get_power_state(task)
        except exception.IloOperationError as ilo_exception:
            operation = (_("Inspecting hardware (get_power_state) on %s") %
                         task.node.uuid)
            raise exception.IloOperationError(operation=operation,
                                              error=ilo_exception)
        if state != states.POWER_ON:
            LOG.info(
                _LI("The node %s is not powered on. Powering on the "
                    "node for inspection."), task.node.uuid)
            conductor_utils.node_power_action(task, states.POWER_ON)
            power_turned_on = True

        # get the essential properties and update the node properties
        # with it.

        inspected_properties = {}
        result = _get_essential_properties(task.node, ilo_object)
        properties = result['properties']
        for known_property in self.ESSENTIAL_PROPERTIES:
            inspected_properties[known_property] = properties[known_property]
        node_properties = task.node.properties
        node_properties.update(inspected_properties)
        task.node.properties = node_properties

        # Inspect the hardware for additional hardware capabilities.
        # Since additional hardware capabilities may not apply to all the
        # hardwares, the method inspect_hardware() doesn't raise an error
        # for these capabilities.
        capabilities = _get_capabilities(task.node, ilo_object)
        if capabilities:
            valid_cap = _create_supported_capabilities_dict(capabilities)
            capabilities = utils.get_updated_capabilities(
                task.node.properties.get('capabilities'), valid_cap)
            if capabilities:
                node_properties['capabilities'] = capabilities
                task.node.properties = node_properties

        task.node.save()

        # Create ports for the nics detected.
        _create_ports_if_not_exist(task.node, result['macs'])

        LOG.debug(("Node properties for %(node)s are updated as "
                   "%(properties)s"), {
                       'properties': inspected_properties,
                       'node': task.node.uuid
                   })

        LOG.info(_LI("Node %s inspected."), task.node.uuid)
        if power_turned_on:
            conductor_utils.node_power_action(task, states.POWER_OFF)
            LOG.info(
                _LI("The node %s was powered on for inspection. "
                    "Powered off the node as inspection completed."),
                task.node.uuid)
        return states.MANAGEABLE
Beispiel #17
0
    def inspect_hardware(self, task):
        """Inspect hardware to get the hardware properties.

        Inspects hardware to get the essential and additional hardware
        properties. It fails if any of the essential properties
        are not received from the node.  It doesn't fail if node fails
        to return any capabilities as the capabilities differ from hardware
        to hardware mostly.

        :param task: a TaskManager instance.
        :raises: HardwareInspectionFailure if essential properties
                 could not be retrieved successfully.
        :raises: IloOperationError if system fails to get power state.
        :returns: The resulting state of inspection.

        """
        power_turned_on = False
        ilo_object = ilo_common.get_ilo_object(task.node)
        try:
            state = task.driver.power.get_power_state(task)
        except exception.IloOperationError as ilo_exception:
            operation = (_("Inspecting hardware (get_power_state) on %s")
                         % task.node.uuid)
            raise exception.IloOperationError(operation=operation,
                                              error=ilo_exception)
        if state != states.POWER_ON:
            LOG.info("The node %s is not powered on. Powering on the "
                     "node for inspection.", task.node.uuid)
            conductor_utils.node_power_action(task, states.POWER_ON)
            power_turned_on = True

        # get the essential properties and update the node properties
        # with it.

        inspected_properties = {}
        result = _get_essential_properties(task.node, ilo_object)

        # A temporary hook for OOB inspection to not to update 'local_gb'
        # for hardware if the storage is a "Direct Attached Storage" or
        # "Dynamic Smart Array Controllers" and the operator has manually
        # updated the local_gb in node properties prior to node inspection.
        # This will be removed once we have inband inspection support for
        # ilo drivers.
        current_local_gb = task.node.properties.get('local_gb')
        properties = result['properties']
        if current_local_gb:
            if properties['local_gb'] == 0 and current_local_gb > 0:
                properties['local_gb'] = current_local_gb
                LOG.warning('Could not discover size of disk on the node '
                            '%s. Value of `properties/local_gb` of the '
                            'node is not overwritten.', task.node.uuid)

        for known_property in self.ESSENTIAL_PROPERTIES:
            inspected_properties[known_property] = properties[known_property]
        node_properties = task.node.properties
        node_properties.update(inspected_properties)
        task.node.properties = node_properties

        # Inspect the hardware for additional hardware capabilities.
        # Since additional hardware capabilities may not apply to all the
        # hardwares, the method inspect_hardware() doesn't raise an error
        # for these capabilities.
        capabilities = _get_capabilities(task.node, ilo_object)
        if capabilities:
            valid_cap = _create_supported_capabilities_dict(capabilities)
            capabilities = utils.get_updated_capabilities(
                task.node.properties.get('capabilities'), valid_cap)
            if capabilities:
                node_properties['capabilities'] = capabilities
                task.node.properties = node_properties

        task.node.save()

        # Create ports for the nics detected.
        _create_ports_if_not_exist(task, result['macs'])

        LOG.debug("Node properties for %(node)s are updated as "
                  "%(properties)s",
                  {'properties': inspected_properties,
                   'node': task.node.uuid})

        LOG.info("Node %s inspected.", task.node.uuid)
        if power_turned_on:
            conductor_utils.node_power_action(task, states.POWER_OFF)
            LOG.info("The node %s was powered on for inspection. "
                     "Powered off the node as inspection completed.",
                     task.node.uuid)
        return states.MANAGEABLE
Beispiel #18
0
    def inspect_hardware(self, task):
        """Inspect hardware to get the hardware properties.

        Inspects hardware to get the essential properties.
        It fails if any of the essential properties
        are not received from the node.

        :param task: a TaskManager instance.
        :raises: HardwareInspectionFailure if essential properties
                 could not be retrieved successfully.
        :returns: The resulting state of inspection.

        """
        system = redfish_utils.get_system(task.node)

        # get the essential properties and update the node properties
        # with it.
        inspected_properties = task.node.properties

        if system.memory_summary and system.memory_summary.size_gib:
            inspected_properties['memory_mb'] = str(
                system.memory_summary.size_gib * units.Ki)

        if system.processors and system.processors.summary:
            cpus, arch = system.processors.summary
            if cpus:
                inspected_properties['cpus'] = cpus

            if arch:
                try:
                    inspected_properties['cpu_arch'] = CPU_ARCH_MAP[arch]

                except KeyError:
                    LOG.warning(
                        "Unknown CPU arch %(arch)s discovered "
                        "for node %(node)s", {
                            'node': task.node.uuid,
                            'arch': arch
                        })

        simple_storage_size = 0

        try:
            LOG.debug(
                "Attempting to discover system simple storage size for "
                "node %(node)s", {'node': task.node.uuid})
            if (system.simple_storage
                    and system.simple_storage.disks_sizes_bytes):
                simple_storage_size = [
                    size for size in system.simple_storage.disks_sizes_bytes
                    if size >= 4 * units.Gi
                ] or [0]

                simple_storage_size = simple_storage_size[0]

        except sushy.exceptions.SushyError as ex:
            LOG.debug(
                "No simple storage information discovered "
                "for node %(node)s: %(err)s", {
                    'node': task.node.uuid,
                    'err': ex
                })

        storage_size = 0

        try:
            LOG.debug(
                "Attempting to discover system storage volume size for "
                "node %(node)s", {'node': task.node.uuid})
            if system.storage and system.storage.volumes_sizes_bytes:
                storage_size = [
                    size for size in system.storage.volumes_sizes_bytes
                    if size >= 4 * units.Gi
                ] or [0]

                storage_size = storage_size[0]

        except sushy.exceptions.SushyError as ex:
            LOG.debug(
                "No storage volume information discovered "
                "for node %(node)s: %(err)s", {
                    'node': task.node.uuid,
                    'err': ex
                })

        try:
            if not storage_size:
                LOG.debug(
                    "Attempting to discover system storage drive size "
                    "for node %(node)s", {'node': task.node.uuid})
                if system.storage and system.storage.drives_sizes_bytes:
                    storage_size = [
                        size for size in system.storage.drives_sizes_bytes
                        if size >= 4 * units.Gi
                    ] or [0]

                    storage_size = storage_size[0]

        except sushy.exceptions.SushyError as ex:
            LOG.debug(
                "No storage drive information discovered "
                "for node %(node)s: %(err)s", {
                    'node': task.node.uuid,
                    'err': ex
                })

        # NOTE(etingof): pick the smallest disk larger than 4G among available
        if simple_storage_size and storage_size:
            local_gb = min(simple_storage_size, storage_size)

        else:
            local_gb = max(simple_storage_size, storage_size)

        # Note(deray): Convert the received size to GiB and reduce the
        # value by 1 GB as consumers like Ironic requires the ``local_gb``
        # to be returned 1 less than actual size.
        local_gb = max(0, int(local_gb / units.Gi - 1))

        # TODO(etingof): should we respect root device hints here?

        if local_gb:
            inspected_properties['local_gb'] = str(local_gb)
        else:
            LOG.warning(
                "Could not provide a valid storage size configured "
                "for node %(node)s. Assuming this is a disk-less node",
                {'node': task.node.uuid})
            inspected_properties['local_gb'] = '0'

        if system.boot.mode:
            if not drivers_utils.get_node_capability(task.node, 'boot_mode'):
                capabilities = utils.get_updated_capabilities(
                    inspected_properties.get('capabilities', ''),
                    {'boot_mode': BOOT_MODE_MAP[system.boot.mode]})

                inspected_properties['capabilities'] = capabilities

        valid_keys = self.ESSENTIAL_PROPERTIES
        missing_keys = valid_keys - set(inspected_properties)
        if missing_keys:
            error = (_('Failed to discover the following properties: '
                       '%(missing_keys)s on node %(node)s'), {
                           'missing_keys': ', '.join(missing_keys),
                           'node': task.node.uuid
                       })
            raise exception.HardwareInspectionFailure(error=error)

        task.node.properties = inspected_properties
        task.node.save()

        LOG.debug(
            "Node properties for %(node)s are updated as "
            "%(properties)s", {
                'properties': inspected_properties,
                'node': task.node.uuid
            })

        if (system.ethernet_interfaces and system.ethernet_interfaces.summary):
            macs = system.ethernet_interfaces.summary

            # Create ports for the discovered NICs being in 'enabled' state
            enabled_macs = {
                nic_mac: nic_state
                for nic_mac, nic_state in macs.items()
                if nic_state == sushy.STATE_ENABLED
            }
            if enabled_macs:
                inspect_utils.create_ports_if_not_exist(
                    task, enabled_macs, get_mac_address=lambda x: x[0])
            else:
                LOG.warning(
                    "Not attempting to create any port as no NICs "
                    "were discovered in 'enabled' state for node "
                    "%(node)s: %(mac_data)s", {
                        'mac_data': macs,
                        'node': task.node.uuid
                    })
        else:
            LOG.warning("No NIC information discovered "
                        "for node %(node)s", {'node': task.node.uuid})

        return states.MANAGEABLE
Beispiel #19
0
    def inspect_hardware(self, task):
        """Inspect hardware.

        Inspect hardware to obtain the essential & additional hardware
        properties.

        :param task: a TaskManager instance containing the node to act on.
        :raises: HardwareInspectionFailure, if unable to get essential
                 hardware properties.
        :returns: states.MANAGEABLE
        """

        node = task.node
        client = drac_common.get_drac_client(node)
        properties = {}

        try:
            properties['memory_mb'] = sum(
                [memory.size_mb for memory in client.list_memory()])
            cpus = client.list_cpus()
            if cpus:
                properties['cpus'] = sum(
                    [self._calculate_cpus(cpu) for cpu in cpus])
                properties['cpu_arch'] = 'x86_64' if cpus[0].arch64 else 'x86'

            bios_settings = client.list_bios_settings()
            video_controllers = client.list_video_controllers()
            current_capabilities = node.properties.get('capabilities', '')
            new_capabilities = {
                'boot_mode': bios_settings["BootMode"].current_value.lower(),
                'pci_gpu_devices': self._calculate_gpus(video_controllers)
            }

            capabilties = utils.get_updated_capabilities(
                current_capabilities, new_capabilities)
            properties['capabilities'] = capabilties

            virtual_disks = client.list_virtual_disks()
            root_disk = self._guess_root_disk(virtual_disks)
            if root_disk:
                properties['local_gb'] = int(root_disk.size_mb / units.Ki)
            else:
                physical_disks = client.list_physical_disks()
                root_disk = self._guess_root_disk(physical_disks)
                if root_disk:
                    properties['local_gb'] = int(root_disk.size_mb / units.Ki)
        except drac_exceptions.BaseClientException as exc:
            LOG.error(
                'DRAC driver failed to introspect node '
                '%(node_uuid)s. Reason: %(error)s.', {
                    'node_uuid': node.uuid,
                    'error': exc
                })
            raise exception.HardwareInspectionFailure(error=exc)

        valid_keys = self.ESSENTIAL_PROPERTIES
        missing_keys = valid_keys - set(properties)
        if missing_keys:
            error = (_('Failed to discover the following properties: '
                       '%(missing_keys)s') % {
                           'missing_keys': ', '.join(missing_keys)
                       })
            raise exception.HardwareInspectionFailure(error=error)

        node.properties = dict(node.properties, **properties)
        node.save()

        try:
            nics = client.list_nics()
        except drac_exceptions.BaseClientException as exc:
            LOG.error(
                'DRAC driver failed to introspect node '
                '%(node_uuid)s. Reason: %(error)s.', {
                    'node_uuid': node.uuid,
                    'error': exc
                })
            raise exception.HardwareInspectionFailure(error=exc)

        pxe_dev_nics = self._get_pxe_dev_nics(client, nics, node)
        if pxe_dev_nics is None:
            LOG.warning(
                'No PXE enabled NIC was found for node '
                '%(node_uuid)s.', {'node_uuid': node.uuid})

        for nic in nics:
            try:
                port = objects.Port(task.context,
                                    address=nic.mac,
                                    node_id=node.id,
                                    pxe_enabled=(nic.id in pxe_dev_nics))
                port.create()

                LOG.info(
                    'Port created with MAC address %(mac)s '
                    'for node %(node_uuid)s during inspection', {
                        'mac': nic.mac,
                        'node_uuid': node.uuid
                    })
            except exception.MACAlreadyExists:
                LOG.warning(
                    'Failed to create a port with MAC address '
                    '%(mac)s when inspecting the node '
                    '%(node_uuid)s because the address is already '
                    'registered', {
                        'mac': nic.mac,
                        'node_uuid': node.uuid
                    })

        LOG.info('Node %s successfully inspected.', node.uuid)
        return states.MANAGEABLE
Beispiel #20
0
    def inspect_hardware(self, task):
        """Inspect hardware to get the hardware properties.

        Inspects hardware to get the essential and additional hardware
        properties. It fails if any of the essential properties
        are not received from the node.  It doesn't fail if node fails
        to return any capabilities as the capabilities differ from hardware
        to hardware mostly.

        :param task: a TaskManager instance.
        :raises: HardwareInspectionFailure if essential properties
                 could not be retrieved successfully.
        :raises: IloOperationError if system fails to get power state.
        :returns: The resulting state of inspection.

        """
        power_turned_on = False
        ilo_object = ilo_common.get_ilo_object(task.node)
        try:
            state = task.driver.power.get_power_state(task)
        except exception.IloOperationError as ilo_exception:
            operation = (_("Inspecting hardware (get_power_state) on %s") %
                         task.node.uuid)
            raise exception.IloOperationError(operation=operation,
                                              error=ilo_exception)
        if state != states.POWER_ON:
            LOG.info(
                "The node %s is not powered on. Powering on the "
                "node for inspection.", task.node.uuid)
            conductor_utils.node_power_action(task, states.POWER_ON)
            power_turned_on = True

        # get the essential properties and update the node properties
        # with it.

        inspected_properties = {}
        result = _get_essential_properties(task.node, ilo_object)

        # A temporary hook for OOB inspection to not to update 'local_gb'
        # for hardware if the storage is a "Direct Attached Storage" or
        # "Dynamic Smart Array Controllers" and the operator has manually
        # updated the local_gb in node properties prior to node inspection.
        # This will be removed once we have inband inspection support for
        # ilo drivers.
        current_local_gb = task.node.properties.get('local_gb')
        properties = result['properties']
        if current_local_gb:
            if properties['local_gb'] == 0 and current_local_gb > 0:
                properties['local_gb'] = current_local_gb
                LOG.warning(
                    'Could not discover size of disk on the node '
                    '%s. Value of `properties/local_gb` of the '
                    'node is not overwritten.', task.node.uuid)

        for known_property in self.ESSENTIAL_PROPERTIES:
            inspected_properties[known_property] = properties[known_property]
        node_properties = task.node.properties
        node_properties.update(inspected_properties)
        task.node.properties = node_properties

        # Inspect the hardware for additional hardware capabilities.
        # Since additional hardware capabilities may not apply to all the
        # hardwares, the method inspect_hardware() doesn't raise an error
        # for these capabilities.
        capabilities = _get_capabilities(task.node, ilo_object)
        model = None
        if capabilities:
            model = capabilities.get('server_model')
            valid_cap = _create_supported_capabilities_dict(capabilities)
            capabilities = utils.get_updated_capabilities(
                task.node.properties.get('capabilities'), valid_cap)
            if capabilities:
                node_properties['capabilities'] = capabilities
                task.node.properties = node_properties

        # RIBCL(Gen8) protocol cannot determine if a NIC
        # is physically connected with cable or not when the server
        # is not provisioned. RIS(Gen9) can detect the same for few NIC
        # adapters but not for all. However it is possible to determine
        # the same using Redfish(Gen10) protocol. Hence proliantutils
        # returns ALL MACs for Gen8 and Gen9 while it returns
        # only active MACs for Gen10. A warning is being added
        # for the user so that he knows that he needs to remove the
        # ironic ports created for inactive ports for Gen8 and Gen9.
        servers = ['Gen8', 'Gen9']
        if model is not None and any(serv in model for serv in servers):
            LOG.warning(
                'iLO cannot determine if the NICs are physically '
                'connected or not for ProLiant Gen8 and Gen9 servers. '
                'Hence returns all the MACs present on the server. '
                'Please remove the ironic ports created for inactive '
                'NICs manually for the node %(node)s',
                {"node": task.node.uuid})
        task.node.save()

        # Create ports for the nics detected.
        inspect_utils.create_ports_if_not_exist(task, result['macs'])

        LOG.debug(
            "Node properties for %(node)s are updated as "
            "%(properties)s", {
                'properties': inspected_properties,
                'node': task.node.uuid
            })

        LOG.info("Node %s inspected.", task.node.uuid)
        if power_turned_on:
            conductor_utils.node_power_action(task, states.POWER_OFF)
            LOG.info(
                "The node %s was powered on for inspection. "
                "Powered off the node as inspection completed.",
                task.node.uuid)
        return states.MANAGEABLE
Beispiel #21
0
    def _test_inspect_hardware_props(self, gpu_ids,
                                     fpga_ids,
                                     existed_capabilities,
                                     inspected_capabilities,
                                     expected_capabilities,
                                     existed_traits,
                                     expected_traits,
                                     get_irmc_report_mock,
                                     scci_mock,
                                     _get_mac_addresses_mock,
                                     trait_mock):
        capabilities_props = set(irmc_inspect.CAPABILITIES_PROPERTIES)

        # if gpu_ids = [], pci_gpu_devices will not be inspected
        if len(gpu_ids) == 0:
            capabilities_props.remove('pci_gpu_devices')

        # if fpga_ids = [], cpu_fpga will not be inspected
        if fpga_ids is None or len(fpga_ids) == 0:
            capabilities_props.remove('cpu_fpga')

        self.config(gpu_ids=gpu_ids, group='irmc')
        self.config(fpga_ids=fpga_ids, group='irmc')
        kwargs = {'sleep_flag': False}

        inspected_props = {
            'memory_mb': '1024',
            'local_gb': 10,
            'cpus': 2,
            'cpu_arch': 'x86_64'}

        inspected_macs = ['aa:aa:aa:aa:aa:aa', 'bb:bb:bb:bb:bb:bb']
        report = 'fake_report'

        get_irmc_report_mock.return_value = report
        scci_mock.get_essential_properties.return_value = inspected_props
        scci_mock.get_capabilities_properties.return_value = \
            inspected_capabilities
        _get_mac_addresses_mock.return_value = inspected_macs
        trait_mock.return_value = existed_traits

        with task_manager.acquire(self.context, self.node.uuid,
                                  shared=True) as task:
            task.node.properties[u'capabilities'] =\
                ",".join('%(k)s:%(v)s' % {'k': k, 'v': v}
                         for k, v in existed_capabilities.items())
            result = irmc_inspect._inspect_hardware(task.node,
                                                    existed_traits,
                                                    **kwargs)
            get_irmc_report_mock.assert_called_once_with(task.node)
            scci_mock.get_essential_properties.assert_called_once_with(
                report, irmc_inspect.IRMCInspect.ESSENTIAL_PROPERTIES)
            scci_mock.get_capabilities_properties.assert_called_once_with(
                mock.ANY, capabilities_props,
                gpu_ids, fpga_ids=fpga_ids, **kwargs)
            expected_capabilities = utils.get_updated_capabilities(
                '', expected_capabilities)

            set1 = set(expected_capabilities.split(','))
            set2 = set(result[0]['capabilities'].split(','))
            self.assertEqual(set1, set2)
            self.assertEqual(expected_traits, result[2])
Beispiel #22
0
    def inspect_hardware(self, task):
        """Inspect hardware to get the hardware properties.

        Inspects hardware to get the essential properties.
        It fails if any of the essential properties
        are not received from the node.

        :param task: a TaskManager instance.
        :raises: HardwareInspectionFailure if essential properties
                 could not be retrieved successfully.
        :returns: The resulting state of inspection.

        """
        system = redfish_utils.get_system(task.node)

        # get the essential properties and update the node properties
        # with it.
        inspected_properties = task.node.properties

        if system.memory_summary and system.memory_summary.size_gib:
            inspected_properties['memory_mb'] = str(
                system.memory_summary.size_gib * units.Ki)

        if system.processors and system.processors.summary:
            cpus, arch = system.processors.summary
            if cpus:
                inspected_properties['cpus'] = cpus

            if arch:
                try:
                    inspected_properties['cpu_arch'] = CPU_ARCH_MAP[arch]

                except KeyError:
                    LOG.warning("Unknown CPU arch %(arch)s discovered "
                                "for node %(node)s", {'node': task.node.uuid,
                                                      'arch': arch})

        simple_storage_size = 0

        try:
            LOG.debug("Attempting to discover system simple storage size for "
                      "node %(node)s", {'node': task.node.uuid})
            if (system.simple_storage and
                    system.simple_storage.disks_sizes_bytes):
                simple_storage_size = [
                    size for size in system.simple_storage.disks_sizes_bytes
                    if size >= 4 * units.Gi
                ] or [0]

                simple_storage_size = simple_storage_size[0]

        except sushy.exceptions.SushyError as ex:
            LOG.debug("No simple storage information discovered "
                      "for node %(node)s: %(err)s", {'node': task.node.uuid,
                                                     'err': ex})

        storage_size = 0

        try:
            LOG.debug("Attempting to discover system storage volume size for "
                      "node %(node)s", {'node': task.node.uuid})
            if system.storage and system.storage.volumes_sizes_bytes:
                storage_size = [
                    size for size in system.storage.volumes_sizes_bytes
                    if size >= 4 * units.Gi
                ] or [0]

                storage_size = storage_size[0]

        except sushy.exceptions.SushyError as ex:
            LOG.debug("No storage volume information discovered "
                      "for node %(node)s: %(err)s", {'node': task.node.uuid,
                                                     'err': ex})

        try:
            if not storage_size:
                LOG.debug("Attempting to discover system storage drive size "
                          "for node %(node)s", {'node': task.node.uuid})
                if system.storage and system.storage.drives_sizes_bytes:
                    storage_size = [
                        size for size in system.storage.drives_sizes_bytes
                        if size >= 4 * units.Gi
                    ] or [0]

                    storage_size = storage_size[0]

        except sushy.exceptions.SushyError as ex:
            LOG.debug("No storage drive information discovered "
                      "for node %(node)s: %(err)s", {'node': task.node.uuid,
                                                     'err': ex})

        # NOTE(etingof): pick the smallest disk larger than 4G among available
        if simple_storage_size and storage_size:
            local_gb = min(simple_storage_size, storage_size)

        else:
            local_gb = max(simple_storage_size, storage_size)

        # Note(deray): Convert the received size to GiB and reduce the
        # value by 1 GB as consumers like Ironic requires the ``local_gb``
        # to be returned 1 less than actual size.
        local_gb = max(0, int(local_gb / units.Gi - 1))

        # TODO(etingof): should we respect root device hints here?

        if local_gb:
            inspected_properties['local_gb'] = str(local_gb)
        else:
            LOG.warning("Could not provide a valid storage size configured "
                        "for node %(node)s. Assuming this is a disk-less node",
                        {'node': task.node.uuid})
            inspected_properties['local_gb'] = '0'

        if system.boot.mode:
            if not drivers_utils.get_node_capability(task.node, 'boot_mode'):
                capabilities = utils.get_updated_capabilities(
                    inspected_properties.get('capabilities', ''),
                    {'boot_mode': BOOT_MODE_MAP[system.boot.mode]})

                inspected_properties['capabilities'] = capabilities

        valid_keys = self.ESSENTIAL_PROPERTIES
        missing_keys = valid_keys - set(inspected_properties)
        if missing_keys:
            error = (_('Failed to discover the following properties: '
                       '%(missing_keys)s on node %(node)s'),
                     {'missing_keys': ', '.join(missing_keys),
                      'node': task.node.uuid})
            raise exception.HardwareInspectionFailure(error=error)

        task.node.properties = inspected_properties
        task.node.save()

        LOG.debug("Node properties for %(node)s are updated as "
                  "%(properties)s", {'properties': inspected_properties,
                                     'node': task.node.uuid})

        if (system.ethernet_interfaces and
                system.ethernet_interfaces.summary):
            macs = system.ethernet_interfaces.summary

            # Create ports for the discovered NICs being in 'enabled' state
            enabled_macs = {nic_mac: nic_state
                            for nic_mac, nic_state in macs.items()
                            if nic_state == sushy.STATE_ENABLED}
            if enabled_macs:
                inspect_utils.create_ports_if_not_exist(
                    task, enabled_macs, get_mac_address=lambda x: x[0])
            else:
                LOG.warning("Not attempting to create any port as no NICs "
                            "were discovered in 'enabled' state for node "
                            "%(node)s: %(mac_data)s",
                            {'mac_data': macs, 'node': task.node.uuid})
        else:
            LOG.warning("No NIC information discovered "
                        "for node %(node)s", {'node': task.node.uuid})

        return states.MANAGEABLE
Beispiel #23
0
 def test_get_updated_capabilities(self):
     capabilities = {'ilo_firmware_version': 'xyz'}
     cap_string = 'ilo_firmware_version:xyz'
     cap_returned = utils.get_updated_capabilities(None, capabilities)
     self.assertEqual(cap_string, cap_returned)
     self.assertIsInstance(cap_returned, str)
Beispiel #24
0
    def inspect_hardware(self, task):
        """Inspect hardware.

        Inspect hardware to obtain the essential & additional hardware
        properties.

        :param task: a TaskManager instance containing the node to act on.
        :raises: HardwareInspectionFailure, if unable to get essential
                 hardware properties.
        :returns: states.MANAGEABLE
        """

        node = task.node
        client = drac_common.get_drac_client(node)
        properties = {}

        try:
            properties['memory_mb'] = sum(
                [memory.size_mb for memory in client.list_memory()])
            cpus = client.list_cpus()
            if cpus:
                properties['cpus'] = sum(
                    [self._calculate_cpus(cpu) for cpu in cpus])
                properties['cpu_arch'] = 'x86_64' if cpus[0].arch64 else 'x86'

            bios_settings = client.list_bios_settings()
            current_capabilities = node.properties.get('capabilities', '')
            new_capabilities = {
                'boot_mode': bios_settings["BootMode"].current_value.lower()}
            capabilties = utils.get_updated_capabilities(current_capabilities,
                                                         new_capabilities)
            properties['capabilities'] = capabilties

            virtual_disks = client.list_virtual_disks()
            root_disk = self._guess_root_disk(virtual_disks)
            if root_disk:
                properties['local_gb'] = int(root_disk.size_mb / units.Ki)
            else:
                physical_disks = client.list_physical_disks()
                root_disk = self._guess_root_disk(physical_disks)
                if root_disk:
                    properties['local_gb'] = int(
                        root_disk.size_mb / units.Ki)
        except drac_exceptions.BaseClientException as exc:
            LOG.error('DRAC driver failed to introspect node '
                      '%(node_uuid)s. Reason: %(error)s.',
                      {'node_uuid': node.uuid, 'error': exc})
            raise exception.HardwareInspectionFailure(error=exc)

        valid_keys = self.ESSENTIAL_PROPERTIES
        missing_keys = valid_keys - set(properties)
        if missing_keys:
            error = (_('Failed to discover the following properties: '
                       '%(missing_keys)s') %
                     {'missing_keys': ', '.join(missing_keys)})
            raise exception.HardwareInspectionFailure(error=error)

        node.properties = dict(node.properties, **properties)
        node.save()

        try:
            nics = client.list_nics()
        except drac_exceptions.BaseClientException as exc:
            LOG.error('DRAC driver failed to introspect node '
                      '%(node_uuid)s. Reason: %(error)s.',
                      {'node_uuid': node.uuid, 'error': exc})
            raise exception.HardwareInspectionFailure(error=exc)

        pxe_dev_nics = self._get_pxe_dev_nics(client, nics, node)
        if pxe_dev_nics is None:
            LOG.warning('No PXE enabled NIC was found for node '
                        '%(node_uuid)s.', {'node_uuid': node.uuid})

        for nic in nics:
            try:
                port = objects.Port(task.context, address=nic.mac,
                                    node_id=node.id,
                                    pxe_enabled=(nic.id in pxe_dev_nics))
                port.create()

                LOG.info('Port created with MAC address %(mac)s '
                         'for node %(node_uuid)s during inspection',
                         {'mac': nic.mac, 'node_uuid': node.uuid})
            except exception.MACAlreadyExists:
                LOG.warning('Failed to create a port with MAC address '
                            '%(mac)s when inspecting the node '
                            '%(node_uuid)s because the address is already '
                            'registered',
                            {'mac': nic.mac, 'node_uuid': node.uuid})

        LOG.info('Node %s successfully inspected.', node.uuid)
        return states.MANAGEABLE
Beispiel #25
0
    def inspect_hardware(self, task):
        """Inspect hardware to get the hardware properties.

        Inspects hardware to get the essential and additional hardware
        properties. It fails if any of the essential properties
        are not received from the node.  It doesn't fail if node fails
        to return any capabilities as the capabilities differ from hardware
        to hardware mostly.

        :param task: a TaskManager instance.
        :raises: HardwareInspectionFailure if essential properties
                 could not be retrieved successfully.
        :raises: IloOperationError if system fails to get power state.
        :returns: The resulting state of inspection.

        """
        power_turned_on = False
        ilo_object = ilo_common.get_ilo_object(task.node)
        try:
            state = task.driver.power.get_power_state(task)
        except exception.IloOperationError as ilo_exception:
            operation = (_("Inspecting hardware (get_power_state) on %s")
                         % task.node.uuid)
            raise exception.IloOperationError(operation=operation,
                                              error=ilo_exception)
        if state != states.POWER_ON:
            LOG.info(_LI("The node %s is not powered on. Powering on the "
                         "node for inspection."), task.node.uuid)
            conductor_utils.node_power_action(task, states.POWER_ON)
            power_turned_on = True

        # get the essential properties and update the node properties
        # with it.

        inspected_properties = {}
        result = _get_essential_properties(task.node, ilo_object)

        # A temporary hook for OOB inspection to not to update 'local_gb'
        # for hardware if the storage is a "Direct Attached Storage" or
        # "Dynamic Smart Array Controllers" and the operator has manually
        # updated the local_gb in node properties prior to node inspection.
        # This will be removed once we have inband inspection support for
        # ilo drivers.
        current_local_gb = task.node.properties.get('local_gb')
        properties = result['properties']
        if current_local_gb:
            if properties['local_gb'] == 0 and current_local_gb > 0:
                properties['local_gb'] = current_local_gb
                LOG.warning(_LW('Could not discover size of disk on the node '
                                '%s. Value of `properties/local_gb` of the '
                                'node is not overwritten.'), task.node.uuid)

        for known_property in self.ESSENTIAL_PROPERTIES:
            inspected_properties[known_property] = properties[known_property]
        node_properties = task.node.properties
        node_properties.update(inspected_properties)
        task.node.properties = node_properties

        # Inspect the hardware for additional hardware capabilities.
        # Since additional hardware capabilities may not apply to all the
        # hardwares, the method inspect_hardware() doesn't raise an error
        # for these capabilities.
        capabilities = _get_capabilities(task.node, ilo_object)
        if capabilities:
            valid_cap = _create_supported_capabilities_dict(capabilities)
            capabilities = utils.get_updated_capabilities(
                task.node.properties.get('capabilities'), valid_cap)
            if capabilities:
                node_properties['capabilities'] = capabilities
                task.node.properties = node_properties

        task.node.save()

        # Create ports for the nics detected.
        _create_ports_if_not_exist(task, result['macs'])

        LOG.debug(("Node properties for %(node)s are updated as "
                   "%(properties)s"),
                  {'properties': inspected_properties,
                   'node': task.node.uuid})

        LOG.info(_LI("Node %s inspected."), task.node.uuid)
        if power_turned_on:
            conductor_utils.node_power_action(task, states.POWER_OFF)
            LOG.info(_LI("The node %s was powered on for inspection. "
                         "Powered off the node as inspection completed."),
                     task.node.uuid)
        return states.MANAGEABLE
Beispiel #26
0
    def inspect_hardware(self, task):
        """Inspect hardware to get the hardware properties.

        Inspects hardware to get the essential and additional hardware
        properties. It fails if any of the essential properties
        are not received from the node.  It doesn't fail if node fails
        to return any capabilities as the capabilities differ from hardware
        to hardware mostly.

        :param task: a TaskManager instance.
        :raises: HardwareInspectionFailure if essential properties
                 could not be retrieved successfully.
        :raises: IloOperationError if system fails to get power state.
        :returns: The resulting state of inspection.

        """
        power_turned_on = False
        ilo_object = ilo_common.get_ilo_object(task.node)
        try:
            state = task.driver.power.get_power_state(task)
        except exception.IloOperationError as ilo_exception:
            operation = (_("Inspecting hardware (get_power_state) on %s")
                         % task.node.uuid)
            raise exception.IloOperationError(operation=operation,
                                              error=ilo_exception)
        if state != states.POWER_ON:
            LOG.info(_LI("The node %s is not powered on. Powering on the "
                         "node for inspection."), task.node.uuid)
            conductor_utils.node_power_action(task, states.POWER_ON)
            power_turned_on = True

        # get the essential properties and update the node properties
        # with it.

        inspected_properties = {}
        result = _get_essential_properties(task.node, ilo_object)
        properties = result['properties']
        for known_property in ESSENTIAL_PROPERTIES_KEYS:
            inspected_properties[known_property] = properties[known_property]
        node_properties = task.node.properties
        node_properties.update(inspected_properties)
        task.node.properties = node_properties

        # Inspect the hardware for additional hardware capabilities.
        # Since additional hardware capabilities may not apply to all the
        # hardwares, the method inspect_hardware() doesn't raise an error
        # for these capabilities.
        capabilities = _get_capabilities(task.node, ilo_object)
        if capabilities:
            valid_cap = _create_supported_capabilities_dict(capabilities)
            capabilities = utils.get_updated_capabilities(
                task.node.properties.get('capabilities'), valid_cap)
            if capabilities:
                node_properties['capabilities'] = capabilities
                task.node.properties = node_properties

        task.node.save()

        # Create ports for the nics detected.
        _create_ports_if_not_exist(task.node, result['macs'])

        LOG.debug(("Node properties for %(node)s are updated as "
                   "%(properties)s"),
                  {'properties': inspected_properties,
                   'node': task.node.uuid})

        LOG.info(_LI("Node %s inspected."), task.node.uuid)
        if power_turned_on:
            conductor_utils.node_power_action(task, states.POWER_OFF)
            LOG.info(_LI("The node %s was powered on for inspection. "
                         "Powered off the node as inspection completed."),
                     task.node.uuid)
        return states.MANAGEABLE