diff options
author | Vanou Ishii <ishii.vanou@fujitsu.com> | 2022-06-01 15:25:25 +0900 |
---|---|---|
committer | Vanou Ishii <ishii.vanou@fujitsu.com> | 2022-09-02 22:17:46 +0900 |
commit | 931f13d3c547928d57052eeae1d8d2fb8c6bd194 (patch) | |
tree | 52766866677af96f25fae3a272e99e148234cd89 /ironic/drivers/modules/irmc/common.py | |
parent | 3f624e5caa83acf9b98443cf32cb0cd69143c6e2 (diff) | |
download | ironic-931f13d3c547928d57052eeae1d8d2fb8c6bd194.tar.gz |
Fix iRMC driver to use certification file in HTTPS
This patch modifies iRMC driver to use certification file
when it connects to iRMC via HTTPS
Conflicts:
doc/source/admin/drivers/irmc.rst
driver-requirements.txt
ironic/drivers/modules/irmc/common.py
ironic/drivers/modules/irmc/raid.py
ironic/tests/unit/drivers/modules/irmc/test_common.py
ironic/tests/unit/drivers/modules/irmc/test_power.py
releasenotes/notes/irmc-add-certification-file-option-34e7a0062c768e58.yaml
Change-Id: If69ce1cf2789d9d60fb8e544596cf7d29eab514d
Co-authored-by: Kobayashi Daisuke <kobayashi.da-06@fujitsu.com>
Co-authored-by: Song Shukun <song.shukun@jp.fujitsu.com>
Story: 2009801
Task: 44345
(cherry picked from commit 64d7a7f3077bc000a18c4a0c56f122941b262483)
(cherry picked from commit 6c0152afa141d05ee28cba81178622021574ae17)
Diffstat (limited to 'ironic/drivers/modules/irmc/common.py')
-rw-r--r-- | ironic/drivers/modules/irmc/common.py | 127 |
1 files changed, 112 insertions, 15 deletions
diff --git a/ironic/drivers/modules/irmc/common.py b/ironic/drivers/modules/irmc/common.py index 0027bab97..5b4ae385d 100644 --- a/ironic/drivers/modules/irmc/common.py +++ b/ironic/drivers/modules/irmc/common.py @@ -15,15 +15,21 @@ """ Common functionalities shared between different iRMC modules. """ +import os + from oslo_log import log as logging from oslo_utils import importutils +from oslo_utils import strutils +from packaging import version from ironic.common import exception from ironic.common.i18n import _ +from ironic.common import utils from ironic.conf import CONF scci = importutils.try_import('scciclient.irmc.scci') elcm = importutils.try_import('scciclient.irmc.elcm') +scci_mod = importutils.try_import('scciclient') LOG = logging.getLogger(__name__) REQUIRED_PROPERTIES = { @@ -52,9 +58,36 @@ OPTIONAL_PROPERTIES = { 'irmc_snmp_security': _("SNMP security name required for version 'v3'. " "Optional."), } +OPTIONAL_DRIVER_INFO_PROPERTIES = { + 'irmc_verify_ca': _('Either a Boolean value, a path to a CA_BUNDLE ' + 'file or directory with certificates of trusted ' + 'CAs. If set to True the driver will verify the ' + 'host certificates; if False the driver will ' + 'ignore verifying the SSL certificate. If it\'s ' + 'a path the driver will use the specified ' + 'certificate or one of the certificates in the ' + 'directory. Defaults to True. Optional'), +} COMMON_PROPERTIES = REQUIRED_PROPERTIES.copy() COMMON_PROPERTIES.update(OPTIONAL_PROPERTIES) +COMMON_PROPERTIES.update(OPTIONAL_DRIVER_INFO_PROPERTIES) + +SCCI_CERTIFICATION_SUPPORT_VERSION_RANGES = [ + {'min': '0.8.2', 'upp': '0.9.0'}, + {'min': '0.9.4', 'upp': '0.10.0'}, + {'min': '0.10.1', 'upp': '0.11.0'}, + {'min': '0.11.3', 'upp': '0.12.0'}, + {'min': '0.12.0', 'upp': '0.13.0'}] + + +def scci_support_certification(): + scciclient_version = version.parse(scci_mod.__version__) + for rangev in SCCI_CERTIFICATION_SUPPORT_VERSION_RANGES: + if (version.parse(rangev['min']) <= scciclient_version + < version.parse(rangev['upp'])): + return True + return False def parse_driver_info(node): @@ -83,7 +116,11 @@ def parse_driver_info(node): # corresponding config names don't have 'irmc_' prefix opt = {param: info.get(param, CONF.irmc.get(param[len('irmc_'):])) for param in OPTIONAL_PROPERTIES} - d_info = dict(req, **opt) + opt_driver_info = {param: info.get(param) + for param in OPTIONAL_DRIVER_INFO_PROPERTIES} + d_info = dict(req, **opt, **opt_driver_info) + d_info['irmc_port'] = utils.validate_network_port( + d_info['irmc_port'], 'irmc_port') error_msgs = [] if (d_info['irmc_auth_method'].lower() not in ('basic', 'digest')): @@ -125,6 +162,38 @@ def parse_driver_info(node): else: error_msgs.append( _("'irmc_snmp_security' has to be set for SNMP version 3.")) + + verify_ca = d_info.get('irmc_verify_ca') + if verify_ca is None: + d_info['irmc_verify_ca'] = verify_ca = CONF.webserver_verify_ca + + # Check if verify_ca is a Boolean or a file/directory in the file-system + if isinstance(verify_ca, str): + if ((os.path.isdir(verify_ca) and os.path.isabs(verify_ca)) + or (os.path.isfile(verify_ca) and os.path.isabs(verify_ca))): + # If it's fullpath and dir/file, we don't need to do anything + pass + else: + try: + d_info['irmc_verify_ca'] = strutils.bool_from_string( + verify_ca, strict=True) + except ValueError: + error_msgs.append( + _('Invalid value type set in driver_info/' + 'irmc_verify_ca on node %(node)s. ' + 'The value should be a Boolean or the path ' + 'to a file/directory, not "%(value)s"' + ) % {'value': verify_ca, 'node': node.uuid}) + elif isinstance(verify_ca, bool): + # If it's a boolean it's grand, we don't need to do anything + pass + else: + error_msgs.append( + _('Invalid value type set in driver_info/irmc_verify_ca ' + 'on node %(node)s. The value should be a Boolean or the path ' + 'to a file/directory, not "%(value)s"') % {'value': verify_ca, + 'node': node.uuid}) + if error_msgs: msg = (_("The following errors were encountered while parsing " "driver_info:\n%s") % "\n".join(error_msgs)) @@ -144,16 +213,30 @@ def get_irmc_client(node): :raises: InvalidParameterValue on invalid inputs. :raises: MissingParameterValue if some mandatory information is missing on the node + :raises: IRMCOperationError if iRMC operation failed """ driver_info = parse_driver_info(node) - scci_client = scci.get_client( - driver_info['irmc_address'], - driver_info['irmc_username'], - driver_info['irmc_password'], - port=driver_info['irmc_port'], - auth_method=driver_info['irmc_auth_method'], - client_timeout=driver_info['irmc_client_timeout']) + if scci_support_certification(): + scci_client = scci.get_client( + driver_info['irmc_address'], + driver_info['irmc_username'], + driver_info['irmc_password'], + port=driver_info['irmc_port'], + auth_method=driver_info['irmc_auth_method'], + verify=driver_info.get('irmc_verify_ca'), + client_timeout=driver_info['irmc_client_timeout']) + else: + if driver_info['irmc_port'] == 443: + LOG.warning("Installed version of python-scciclient doesn't " + "support certification on HTTPS connection.") + scci_client = scci.get_client( + driver_info['irmc_address'], + driver_info['irmc_username'], + driver_info['irmc_password'], + port=driver_info['irmc_port'], + auth_method=driver_info['irmc_auth_method'], + client_timeout=driver_info['irmc_client_timeout']) return scci_client @@ -189,13 +272,27 @@ def get_irmc_report(node): """ driver_info = parse_driver_info(node) - return scci.get_report( - driver_info['irmc_address'], - driver_info['irmc_username'], - driver_info['irmc_password'], - port=driver_info['irmc_port'], - auth_method=driver_info['irmc_auth_method'], - client_timeout=driver_info['irmc_client_timeout']) + if scci_support_certification(): + report = scci.get_report( + driver_info['irmc_address'], + driver_info['irmc_username'], + driver_info['irmc_password'], + port=driver_info['irmc_port'], + auth_method=driver_info['irmc_auth_method'], + verify=driver_info.get('irmc_verify_ca'), + client_timeout=driver_info['irmc_client_timeout']) + else: + if driver_info['irmc_port'] == 443: + LOG.warning("Installed version of python-scciclient doesn't " + "support certification on HTTPS connection.") + report = scci.get_report( + driver_info['irmc_address'], + driver_info['irmc_username'], + driver_info['irmc_password'], + port=driver_info['irmc_port'], + auth_method=driver_info['irmc_auth_method'], + client_timeout=driver_info['irmc_client_timeout']) + return report def get_secure_boot_mode(node): |