Add a plugin for capabilities detection
Supports boot_mode and CPU flags. Change-Id: Idee87a9fa0c89e51993735e69906f5688bfe23aa Closes-Bug: #1571580
This commit is contained in:
parent
6a1083d7a1
commit
b2c2767147
|
@ -3,6 +3,7 @@ output_file = example.conf
|
||||||
namespace = ironic_inspector
|
namespace = ironic_inspector
|
||||||
namespace = ironic_inspector.common.ironic
|
namespace = ironic_inspector.common.ironic
|
||||||
namespace = ironic_inspector.common.swift
|
namespace = ironic_inspector.common.swift
|
||||||
|
namespace = ironic_inspector.plugins.capabilities
|
||||||
namespace = ironic_inspector.plugins.discovery
|
namespace = ironic_inspector.plugins.discovery
|
||||||
namespace = keystonemiddleware.auth_token
|
namespace = keystonemiddleware.auth_token
|
||||||
namespace = oslo.db
|
namespace = oslo.db
|
||||||
|
|
|
@ -184,15 +184,22 @@ introspection data. Note that order does matter in this option.
|
||||||
These are plugins that are enabled by default and should not be disabled,
|
These are plugins that are enabled by default and should not be disabled,
|
||||||
unless you understand what you're doing:
|
unless you understand what you're doing:
|
||||||
|
|
||||||
``ramdisk_error``
|
|
||||||
reports error, if ``error`` field is set by the ramdisk, also optionally
|
|
||||||
stores logs from ``logs`` field, see :ref:`api` for details.
|
|
||||||
``scheduler``
|
``scheduler``
|
||||||
validates and updates basic hardware scheduling properties: CPU number and
|
validates and updates basic hardware scheduling properties: CPU number and
|
||||||
architecture, memory and disk size.
|
architecture, memory and disk size.
|
||||||
``validate_interfaces``
|
``validate_interfaces``
|
||||||
validates network interfaces information.
|
validates network interfaces information.
|
||||||
|
|
||||||
|
The following plugins are enabled by default, but can be disabled if not
|
||||||
|
needed:
|
||||||
|
|
||||||
|
``ramdisk_error``
|
||||||
|
reports error, if ``error`` field is set by the ramdisk, also optionally
|
||||||
|
stores logs from ``logs`` field, see :ref:`api` for details.
|
||||||
|
``capabilities``
|
||||||
|
detect node capabilities: CPU, boot mode, etc. See `Capabilities
|
||||||
|
Detection`_ for more details.
|
||||||
|
|
||||||
Here are some plugins that can be additionally enabled:
|
Here are some plugins that can be additionally enabled:
|
||||||
|
|
||||||
``example``
|
``example``
|
||||||
|
@ -330,3 +337,42 @@ Limitations:
|
||||||
* the unprocessed data is never cleaned from the store
|
* the unprocessed data is never cleaned from the store
|
||||||
* check for stored data presence is performed in background;
|
* check for stored data presence is performed in background;
|
||||||
missing data situation still results in a ``202`` response
|
missing data situation still results in a ``202`` response
|
||||||
|
|
||||||
|
Capabilities Detection
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
Starting with the Newton release, **Ironic Inspector** can optionally discover
|
||||||
|
several node capabilities. A recent (Newton or newer) IPA image is required
|
||||||
|
for it to work.
|
||||||
|
|
||||||
|
Boot mode
|
||||||
|
^^^^^^^^^
|
||||||
|
|
||||||
|
The current boot mode (BIOS or UEFI) can be detected and recorded as
|
||||||
|
``boot_mode`` capability in Ironic. It will make some drivers to change their
|
||||||
|
behaviour to account for this capability. Set the ``[capabilities]boot_mode``
|
||||||
|
configuration option to ``True`` to enable.
|
||||||
|
|
||||||
|
CPU capabilities
|
||||||
|
^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
Several CPU flags are detected by default and recorded as following
|
||||||
|
capabilities:
|
||||||
|
|
||||||
|
* ``cpu_aes`` AES instructions.
|
||||||
|
|
||||||
|
* ``cpu_vt`` virtualization support.
|
||||||
|
|
||||||
|
* ``cpu_txt`` TXT support.
|
||||||
|
|
||||||
|
* ``cpu_hugepages`` huge pages (2 MiB) support.
|
||||||
|
|
||||||
|
* ``cpu_hugepages_1g`` huge pages (1 GiB) support.
|
||||||
|
|
||||||
|
It is possible to define your own rules for detecting CPU capabilities.
|
||||||
|
Set the ``[capabilities]cpu_flags`` configuration option to a mapping between
|
||||||
|
a CPU flag and a capability, for example::
|
||||||
|
|
||||||
|
cpu_flags = aes:cpu_aes,svm:cpu_vt,vmx:cpu_vt
|
||||||
|
|
||||||
|
See the default value of this option for a more detail example.
|
||||||
|
|
70
example.conf
70
example.conf
|
@ -76,10 +76,11 @@
|
||||||
|
|
||||||
# If set to true, the logging level will be set to DEBUG instead of
|
# If set to true, the logging level will be set to DEBUG instead of
|
||||||
# the default INFO level. (boolean value)
|
# the default INFO level. (boolean value)
|
||||||
|
# Note: This option can be changed without restarting.
|
||||||
#debug = false
|
#debug = false
|
||||||
|
|
||||||
# If set to false, the logging level will be set to WARNING instead of
|
# DEPRECATED: If set to false, the logging level will be set to
|
||||||
# the default INFO level. (boolean value)
|
# WARNING instead of the default INFO level. (boolean value)
|
||||||
# This option is deprecated for removal.
|
# This option is deprecated for removal.
|
||||||
# Its value may be silently ignored in the future.
|
# Its value may be silently ignored in the future.
|
||||||
#verbose = true
|
#verbose = true
|
||||||
|
@ -168,6 +169,20 @@
|
||||||
#fatal_deprecations = false
|
#fatal_deprecations = false
|
||||||
|
|
||||||
|
|
||||||
|
[capabilities]
|
||||||
|
|
||||||
|
#
|
||||||
|
# From ironic_inspector.plugins.capabilities
|
||||||
|
#
|
||||||
|
|
||||||
|
# Whether to store the boot mode (BIOS or UEFI). (boolean value)
|
||||||
|
#boot_mode = false
|
||||||
|
|
||||||
|
# Mapping between a CPU flag and a capability to set if this flag is
|
||||||
|
# present. (dict value)
|
||||||
|
#cpu_flags = aes:cpu_aes,pdpe1gb:cpu_hugepages_1g,pse:cpu_hugepages,smx:cpu_txt,svm:cpu_vt,vmx:cpu_vt
|
||||||
|
|
||||||
|
|
||||||
[cors]
|
[cors]
|
||||||
|
|
||||||
#
|
#
|
||||||
|
@ -175,7 +190,9 @@
|
||||||
#
|
#
|
||||||
|
|
||||||
# Indicate whether this resource may be shared with the domain
|
# Indicate whether this resource may be shared with the domain
|
||||||
# received in the requests "origin" header. (list value)
|
# received in the requests "origin" header. Format:
|
||||||
|
# "<protocol>://<host>[:<port>]", no trailing slash. Example:
|
||||||
|
# https://horizon.example.com (list value)
|
||||||
#allowed_origin = <None>
|
#allowed_origin = <None>
|
||||||
|
|
||||||
# Indicate that the actual request can include user credentials
|
# Indicate that the actual request can include user credentials
|
||||||
|
@ -184,7 +201,7 @@
|
||||||
|
|
||||||
# Indicate which headers are safe to expose to the API. Defaults to
|
# Indicate which headers are safe to expose to the API. Defaults to
|
||||||
# HTTP Simple Headers. (list value)
|
# HTTP Simple Headers. (list value)
|
||||||
#expose_headers = Content-Type,Cache-Control,Content-Language,Expires,Last-Modified,Pragma
|
#expose_headers =
|
||||||
|
|
||||||
# Maximum cache age of CORS preflight requests. (integer value)
|
# Maximum cache age of CORS preflight requests. (integer value)
|
||||||
#max_age = 3600
|
#max_age = 3600
|
||||||
|
@ -205,7 +222,9 @@
|
||||||
#
|
#
|
||||||
|
|
||||||
# Indicate whether this resource may be shared with the domain
|
# Indicate whether this resource may be shared with the domain
|
||||||
# received in the requests "origin" header. (list value)
|
# received in the requests "origin" header. Format:
|
||||||
|
# "<protocol>://<host>[:<port>]", no trailing slash. Example:
|
||||||
|
# https://horizon.example.com (list value)
|
||||||
#allowed_origin = <None>
|
#allowed_origin = <None>
|
||||||
|
|
||||||
# Indicate that the actual request can include user credentials
|
# Indicate that the actual request can include user credentials
|
||||||
|
@ -214,7 +233,7 @@
|
||||||
|
|
||||||
# Indicate which headers are safe to expose to the API. Defaults to
|
# Indicate which headers are safe to expose to the API. Defaults to
|
||||||
# HTTP Simple Headers. (list value)
|
# HTTP Simple Headers. (list value)
|
||||||
#expose_headers = Content-Type,Cache-Control,Content-Language,Expires,Last-Modified,Pragma
|
#expose_headers =
|
||||||
|
|
||||||
# Maximum cache age of CORS preflight requests. (integer value)
|
# Maximum cache age of CORS preflight requests. (integer value)
|
||||||
#max_age = 3600
|
#max_age = 3600
|
||||||
|
@ -340,8 +359,8 @@
|
||||||
# From ironic_inspector
|
# From ironic_inspector
|
||||||
#
|
#
|
||||||
|
|
||||||
# SQLite3 database to store nodes under introspection, required. Do
|
# DEPRECATED: SQLite3 database to store nodes under introspection,
|
||||||
# not use :memory: here, it won't work. DEPRECATED: use
|
# required. Do not use :memory: here, it won't work. DEPRECATED: use
|
||||||
# [database]/connection. (string value)
|
# [database]/connection. (string value)
|
||||||
# This option is deprecated for removal.
|
# This option is deprecated for removal.
|
||||||
# Its value may be silently ignored in the future.
|
# Its value may be silently ignored in the future.
|
||||||
|
@ -423,8 +442,9 @@
|
||||||
# Domain name to scope to (unknown value)
|
# Domain name to scope to (unknown value)
|
||||||
#domain_name = <None>
|
#domain_name = <None>
|
||||||
|
|
||||||
# Keystone admin endpoint. DEPRECATED: Use [keystone_authtoken]
|
# DEPRECATED: Keystone admin endpoint. DEPRECATED: Use
|
||||||
# section for keystone token validation. (string value)
|
# [keystone_authtoken] section for keystone token validation. (string
|
||||||
|
# value)
|
||||||
# Deprecated group/name - [discoverd]/identity_uri
|
# Deprecated group/name - [discoverd]/identity_uri
|
||||||
# This option is deprecated for removal.
|
# This option is deprecated for removal.
|
||||||
# Its value may be silently ignored in the future.
|
# Its value may be silently ignored in the future.
|
||||||
|
@ -445,9 +465,9 @@
|
||||||
# (integer value)
|
# (integer value)
|
||||||
#max_retries = 30
|
#max_retries = 30
|
||||||
|
|
||||||
# Keystone authentication endpoint for accessing Ironic API. Use
|
# DEPRECATED: Keystone authentication endpoint for accessing Ironic
|
||||||
# [keystone_authtoken] section for keystone token validation. (string
|
# API. Use [keystone_authtoken] section for keystone token validation.
|
||||||
# value)
|
# (string value)
|
||||||
# Deprecated group/name - [discoverd]/os_auth_url
|
# Deprecated group/name - [discoverd]/os_auth_url
|
||||||
# This option is deprecated for removal.
|
# This option is deprecated for removal.
|
||||||
# Its value may be silently ignored in the future.
|
# Its value may be silently ignored in the future.
|
||||||
|
@ -457,8 +477,9 @@
|
||||||
# Ironic endpoint type. (string value)
|
# Ironic endpoint type. (string value)
|
||||||
#os_endpoint_type = internalURL
|
#os_endpoint_type = internalURL
|
||||||
|
|
||||||
# Password for accessing Ironic API. Use [keystone_authtoken] section
|
# DEPRECATED: Password for accessing Ironic API. Use
|
||||||
# for keystone token validation. (string value)
|
# [keystone_authtoken] section for keystone token validation. (string
|
||||||
|
# value)
|
||||||
# Deprecated group/name - [discoverd]/os_password
|
# Deprecated group/name - [discoverd]/os_password
|
||||||
# This option is deprecated for removal.
|
# This option is deprecated for removal.
|
||||||
# Its value may be silently ignored in the future.
|
# Its value may be silently ignored in the future.
|
||||||
|
@ -471,16 +492,18 @@
|
||||||
# Ironic service type. (string value)
|
# Ironic service type. (string value)
|
||||||
#os_service_type = baremetal
|
#os_service_type = baremetal
|
||||||
|
|
||||||
# Tenant name for accessing Ironic API. Use [keystone_authtoken]
|
# DEPRECATED: Tenant name for accessing Ironic API. Use
|
||||||
# section for keystone token validation. (string value)
|
# [keystone_authtoken] section for keystone token validation. (string
|
||||||
|
# value)
|
||||||
# Deprecated group/name - [discoverd]/os_tenant_name
|
# Deprecated group/name - [discoverd]/os_tenant_name
|
||||||
# This option is deprecated for removal.
|
# This option is deprecated for removal.
|
||||||
# Its value may be silently ignored in the future.
|
# Its value may be silently ignored in the future.
|
||||||
# Reason: Use options presented by configured keystone auth plugin.
|
# Reason: Use options presented by configured keystone auth plugin.
|
||||||
#os_tenant_name =
|
#os_tenant_name =
|
||||||
|
|
||||||
# User name for accessing Ironic API. Use [keystone_authtoken] section
|
# DEPRECATED: User name for accessing Ironic API. Use
|
||||||
# for keystone token validation. (string value)
|
# [keystone_authtoken] section for keystone token validation. (string
|
||||||
|
# value)
|
||||||
# Deprecated group/name - [discoverd]/os_username
|
# Deprecated group/name - [discoverd]/os_username
|
||||||
# This option is deprecated for removal.
|
# This option is deprecated for removal.
|
||||||
# Its value may be silently ignored in the future.
|
# Its value may be silently ignored in the future.
|
||||||
|
@ -598,7 +621,8 @@
|
||||||
# Determines the frequency at which the list of revoked tokens is
|
# Determines the frequency at which the list of revoked tokens is
|
||||||
# retrieved from the Identity service (in seconds). A high number of
|
# retrieved from the Identity service (in seconds). A high number of
|
||||||
# revocation events combined with a low cache duration may
|
# revocation events combined with a low cache duration may
|
||||||
# significantly reduce performance. (integer value)
|
# significantly reduce performance. Only valid for PKI tokens.
|
||||||
|
# (integer value)
|
||||||
#revocation_cache_time = 10
|
#revocation_cache_time = 10
|
||||||
|
|
||||||
# (Optional) If defined, indicate whether token data should be
|
# (Optional) If defined, indicate whether token data should be
|
||||||
|
@ -718,7 +742,7 @@
|
||||||
# the Nova scheduler. Hook 'validate_interfaces' ensures that valid
|
# the Nova scheduler. Hook 'validate_interfaces' ensures that valid
|
||||||
# NIC data was provided by the ramdisk.Do not exclude these two unless
|
# NIC data was provided by the ramdisk.Do not exclude these two unless
|
||||||
# you really know what you're doing. (string value)
|
# you really know what you're doing. (string value)
|
||||||
#default_processing_hooks = ramdisk_error,root_disk_selection,scheduler,validate_interfaces
|
#default_processing_hooks = ramdisk_error,root_disk_selection,scheduler,validate_interfaces,capabilities
|
||||||
|
|
||||||
# Comma-separated list of enabled hooks for processing pipeline. The
|
# Comma-separated list of enabled hooks for processing pipeline. The
|
||||||
# default for this is $default_processing_hooks, hooks can be added
|
# default for this is $default_processing_hooks, hooks can be added
|
||||||
|
@ -815,13 +839,13 @@
|
||||||
# (integer value)
|
# (integer value)
|
||||||
#max_retries = 2
|
#max_retries = 2
|
||||||
|
|
||||||
# Keystone authentication URL (string value)
|
# DEPRECATED: Keystone authentication URL (string value)
|
||||||
# This option is deprecated for removal.
|
# This option is deprecated for removal.
|
||||||
# Its value may be silently ignored in the future.
|
# Its value may be silently ignored in the future.
|
||||||
# Reason: Use options presented by configured keystone auth plugin.
|
# Reason: Use options presented by configured keystone auth plugin.
|
||||||
#os_auth_url =
|
#os_auth_url =
|
||||||
|
|
||||||
# Keystone authentication API version (string value)
|
# DEPRECATED: Keystone authentication API version (string value)
|
||||||
# This option is deprecated for removal.
|
# This option is deprecated for removal.
|
||||||
# Its value may be silently ignored in the future.
|
# Its value may be silently ignored in the future.
|
||||||
# Reason: Use options presented by configured keystone auth plugin.
|
# Reason: Use options presented by configured keystone auth plugin.
|
||||||
|
|
|
@ -79,7 +79,7 @@ PROCESSING_OPTS = [
|
||||||
deprecated_group='discoverd'),
|
deprecated_group='discoverd'),
|
||||||
cfg.StrOpt('default_processing_hooks',
|
cfg.StrOpt('default_processing_hooks',
|
||||||
default='ramdisk_error,root_disk_selection,scheduler,'
|
default='ramdisk_error,root_disk_selection,scheduler,'
|
||||||
'validate_interfaces',
|
'validate_interfaces,capabilities',
|
||||||
help='Comma-separated list of default hooks for processing '
|
help='Comma-separated list of default hooks for processing '
|
||||||
'pipeline. Hook \'scheduler\' updates the node with the '
|
'pipeline. Hook \'scheduler\' updates the node with the '
|
||||||
'minimum properties required by the Nova scheduler. '
|
'minimum properties required by the Nova scheduler. '
|
||||||
|
|
|
@ -0,0 +1,101 @@
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||||
|
# implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
|
||||||
|
"""Gather capabilities from inventory."""
|
||||||
|
|
||||||
|
from oslo_config import cfg
|
||||||
|
|
||||||
|
from ironic_inspector.common.i18n import _LI, _LW
|
||||||
|
from ironic_inspector.plugins import base
|
||||||
|
from ironic_inspector import utils
|
||||||
|
|
||||||
|
|
||||||
|
DEFAULT_CPU_FLAGS_MAPPING = {
|
||||||
|
'vmx': 'cpu_vt',
|
||||||
|
'svm': 'cpu_vt',
|
||||||
|
'aes': 'cpu_aes',
|
||||||
|
'pse': 'cpu_hugepages',
|
||||||
|
'pdpe1gb': 'cpu_hugepages_1g',
|
||||||
|
'smx': 'cpu_txt',
|
||||||
|
}
|
||||||
|
|
||||||
|
CAPABILITIES_OPTS = [
|
||||||
|
cfg.BoolOpt('boot_mode',
|
||||||
|
default=False,
|
||||||
|
help='Whether to store the boot mode (BIOS or UEFI).'),
|
||||||
|
cfg.DictOpt('cpu_flags',
|
||||||
|
default=DEFAULT_CPU_FLAGS_MAPPING,
|
||||||
|
help='Mapping between a CPU flag and a capability to set '
|
||||||
|
'if this flag is present.'),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def list_opts():
|
||||||
|
return [
|
||||||
|
('capabilities', CAPABILITIES_OPTS)
|
||||||
|
]
|
||||||
|
|
||||||
|
CONF = cfg.CONF
|
||||||
|
CONF.register_opts(CAPABILITIES_OPTS, group='capabilities')
|
||||||
|
LOG = utils.getProcessingLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class CapabilitiesHook(base.ProcessingHook):
|
||||||
|
"""Processing hook for detecting capabilities."""
|
||||||
|
|
||||||
|
def _detect_boot_mode(self, inventory, node_info, data=None):
|
||||||
|
boot_mode = inventory.get('boot', {}).get('current_boot_mode')
|
||||||
|
if boot_mode is not None:
|
||||||
|
LOG.info(_LI('Boot mode was %s'), boot_mode,
|
||||||
|
data=data, node_info=node_info)
|
||||||
|
return {'boot_mode': boot_mode}
|
||||||
|
else:
|
||||||
|
LOG.warning(_LW('No boot mode information available'),
|
||||||
|
data=data, node_info=node_info)
|
||||||
|
return {}
|
||||||
|
|
||||||
|
def _detect_cpu_flags(self, inventory, node_info, data=None):
|
||||||
|
flags = inventory['cpu'].get('flags')
|
||||||
|
if not flags:
|
||||||
|
LOG.warning(_LW('No CPU flags available, please update your '
|
||||||
|
'introspection ramdisk'),
|
||||||
|
data=data, node_info=node_info)
|
||||||
|
return {}
|
||||||
|
|
||||||
|
flags = set(flags)
|
||||||
|
caps = {}
|
||||||
|
for flag, name in CONF.capabilities.cpu_flags.items():
|
||||||
|
if flag in flags:
|
||||||
|
caps[name] = 'true'
|
||||||
|
|
||||||
|
LOG.info(_LI('CPU capabilities: %s'), list(caps),
|
||||||
|
data=data, node_info=node_info)
|
||||||
|
return caps
|
||||||
|
|
||||||
|
def before_update(self, introspection_data, node_info, **kwargs):
|
||||||
|
inventory = utils.get_inventory(introspection_data)
|
||||||
|
caps = {}
|
||||||
|
if CONF.capabilities.boot_mode:
|
||||||
|
caps.update(self._detect_boot_mode(inventory, node_info,
|
||||||
|
introspection_data))
|
||||||
|
|
||||||
|
caps.update(self._detect_cpu_flags(inventory, node_info,
|
||||||
|
introspection_data))
|
||||||
|
|
||||||
|
if caps:
|
||||||
|
LOG.debug('New capabilities: %s', caps, node_info=node_info,
|
||||||
|
data=introspection_data)
|
||||||
|
node_info.update_capabilities(**caps)
|
||||||
|
else:
|
||||||
|
LOG.debug('No new capabilities detected', node_info=node_info,
|
||||||
|
data=introspection_data)
|
|
@ -0,0 +1,77 @@
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||||
|
# implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
|
||||||
|
import mock
|
||||||
|
|
||||||
|
from oslo_config import cfg
|
||||||
|
|
||||||
|
from ironic_inspector import node_cache
|
||||||
|
from ironic_inspector.plugins import base
|
||||||
|
from ironic_inspector.plugins import capabilities
|
||||||
|
from ironic_inspector.test import base as test_base
|
||||||
|
|
||||||
|
|
||||||
|
CONF = cfg.CONF
|
||||||
|
|
||||||
|
|
||||||
|
@mock.patch.object(node_cache.NodeInfo, 'update_capabilities', autospec=True)
|
||||||
|
class TestCapabilitiesHook(test_base.NodeTest):
|
||||||
|
hook = capabilities.CapabilitiesHook()
|
||||||
|
|
||||||
|
def test_loadable_by_name(self, mock_caps):
|
||||||
|
base.CONF.set_override('processing_hooks', 'capabilities',
|
||||||
|
'processing')
|
||||||
|
ext = base.processing_hooks_manager()['capabilities']
|
||||||
|
self.assertIsInstance(ext.obj, capabilities.CapabilitiesHook)
|
||||||
|
|
||||||
|
def test_no_data(self, mock_caps):
|
||||||
|
self.hook.before_update(self.data, self.node_info)
|
||||||
|
self.assertFalse(mock_caps.called)
|
||||||
|
|
||||||
|
def test_boot_mode(self, mock_caps):
|
||||||
|
CONF.set_override('boot_mode', True, 'capabilities')
|
||||||
|
self.inventory['boot'] = {'current_boot_mode': 'uefi'}
|
||||||
|
|
||||||
|
self.hook.before_update(self.data, self.node_info)
|
||||||
|
mock_caps.assert_called_once_with(self.node_info, boot_mode='uefi')
|
||||||
|
|
||||||
|
def test_boot_mode_disabled(self, mock_caps):
|
||||||
|
self.inventory['boot'] = {'current_boot_mode': 'uefi'}
|
||||||
|
|
||||||
|
self.hook.before_update(self.data, self.node_info)
|
||||||
|
self.assertFalse(mock_caps.called)
|
||||||
|
|
||||||
|
def test_cpu_flags(self, mock_caps):
|
||||||
|
self.inventory['cpu']['flags'] = ['fpu', 'vmx', 'aes', 'pse', 'smx']
|
||||||
|
|
||||||
|
self.hook.before_update(self.data, self.node_info)
|
||||||
|
mock_caps.assert_called_once_with(self.node_info,
|
||||||
|
cpu_vt='true',
|
||||||
|
cpu_hugepages='true',
|
||||||
|
cpu_txt='true',
|
||||||
|
cpu_aes='true')
|
||||||
|
|
||||||
|
def test_cpu_no_known_flags(self, mock_caps):
|
||||||
|
self.inventory['cpu']['flags'] = ['fpu']
|
||||||
|
|
||||||
|
self.hook.before_update(self.data, self.node_info)
|
||||||
|
self.assertFalse(mock_caps.called)
|
||||||
|
|
||||||
|
def test_cpu_flags_custom(self, mock_caps):
|
||||||
|
CONF.set_override('cpu_flags', {'fpu': 'new_cap'},
|
||||||
|
'capabilities')
|
||||||
|
self.inventory['cpu']['flags'] = ['fpu', 'vmx', 'aes', 'pse']
|
||||||
|
|
||||||
|
self.hook.before_update(self.data, self.node_info)
|
||||||
|
mock_caps.assert_called_once_with(self.node_info,
|
||||||
|
new_cap='true')
|
|
@ -0,0 +1,4 @@
|
||||||
|
---
|
||||||
|
features:
|
||||||
|
- Added a new "capabilities" processing hook detecting the CPU and boot mode
|
||||||
|
capabilities (the latter disabled by default).
|
|
@ -31,6 +31,7 @@ ironic_inspector.hooks.processing =
|
||||||
example = ironic_inspector.plugins.example:ExampleProcessingHook
|
example = ironic_inspector.plugins.example:ExampleProcessingHook
|
||||||
extra_hardware = ironic_inspector.plugins.extra_hardware:ExtraHardwareHook
|
extra_hardware = ironic_inspector.plugins.extra_hardware:ExtraHardwareHook
|
||||||
raid_device = ironic_inspector.plugins.raid_device:RaidDeviceDetection
|
raid_device = ironic_inspector.plugins.raid_device:RaidDeviceDetection
|
||||||
|
capabilities = ironic_inspector.plugins.capabilities:CapabilitiesHook
|
||||||
# Deprecated name for raid_device, don't confuse with root_disk_selection
|
# Deprecated name for raid_device, don't confuse with root_disk_selection
|
||||||
root_device_hint = ironic_inspector.plugins.raid_device:RootDeviceHintHook
|
root_device_hint = ironic_inspector.plugins.raid_device:RootDeviceHintHook
|
||||||
ironic_inspector.hooks.node_not_found =
|
ironic_inspector.hooks.node_not_found =
|
||||||
|
@ -58,6 +59,7 @@ oslo.config.opts =
|
||||||
ironic_inspector.common.ironic = ironic_inspector.common.ironic:list_opts
|
ironic_inspector.common.ironic = ironic_inspector.common.ironic:list_opts
|
||||||
ironic_inspector.common.swift = ironic_inspector.common.swift:list_opts
|
ironic_inspector.common.swift = ironic_inspector.common.swift:list_opts
|
||||||
ironic_inspector.plugins.discovery = ironic_inspector.plugins.discovery:list_opts
|
ironic_inspector.plugins.discovery = ironic_inspector.plugins.discovery:list_opts
|
||||||
|
ironic_inspector.plugins.capabilities = ironic_inspector.plugins.capabilities:list_opts
|
||||||
oslo.config.opts.defaults =
|
oslo.config.opts.defaults =
|
||||||
ironic_inspector = ironic_inspector.conf:set_config_defaults
|
ironic_inspector = ironic_inspector.conf:set_config_defaults
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue