diff --git a/changelogs/fragments/9964-redfish-tls.yml b/changelogs/fragments/9964-redfish-tls.yml new file mode 100644 index 0000000000..edb8e942ff --- /dev/null +++ b/changelogs/fragments/9964-redfish-tls.yml @@ -0,0 +1,7 @@ +minor_changes: + - "redfish module utils - add ``REDFISH_COMMON_ARGUMENT_SPEC``, a corresponding ``redfish`` docs fragment, and support for its ``validate_certs``, ``ca_path``, and ``ciphers`` options (https://github.com/ansible-collections/community.general/issues/3686, https://github.com/ansible-collections/community.general/pull/9964)." + - "idrac_redfish_command, idrac_redfish_config, idrac_redfish_info - add ``validate_certs``, ``ca_path``, and ``ciphers`` options to configure TLS/SSL (https://github.com/ansible-collections/community.general/issues/3686, https://github.com/ansible-collections/community.general/pull/9964)." + - "ilo_redfish_command, ilo_redfish_config, ilo_redfish_info - add ``validate_certs``, ``ca_path``, and ``ciphers`` options to configure TLS/SSL (https://github.com/ansible-collections/community.general/issues/3686, https://github.com/ansible-collections/community.general/pull/9964)." + - "redfish_command, redfish_config, redfish_info - add ``validate_certs`` and ``ca_path`` options to configure TLS/SSL (https://github.com/ansible-collections/community.general/issues/3686, https://github.com/ansible-collections/community.general/pull/9964)." + - "wdc_redfish_command, wdc_redfish_info - add ``validate_certs``, ``ca_path``, and ``ciphers`` options to configure TLS/SSL (https://github.com/ansible-collections/community.general/issues/3686, https://github.com/ansible-collections/community.general/pull/9964)." + - "xcc_redfish_command - add ``validate_certs``, ``ca_path``, and ``ciphers`` options to configure TLS/SSL (https://github.com/ansible-collections/community.general/issues/3686, https://github.com/ansible-collections/community.general/pull/9964)." diff --git a/plugins/doc_fragments/redfish.py b/plugins/doc_fragments/redfish.py new file mode 100644 index 0000000000..f2e6b37485 --- /dev/null +++ b/plugins/doc_fragments/redfish.py @@ -0,0 +1,37 @@ +# -*- coding: utf-8 -*- + +# Copyright (c) 2025 Ansible community +# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) +# SPDX-License-Identifier: GPL-3.0-or-later + +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + + +class ModuleDocFragment(object): + + # Use together with the community.general.redfish module utils' REDFISH_COMMON_ARGUMENT_SPEC + DOCUMENTATION = r""" +options: + validate_certs: + description: + - If V(false), TLS/SSL certificates will not be validated. + - Set this to V(true) to enable certificate checking. Should be used together with O(ca_path). + type: bool + default: false + ca_path: + description: + - PEM formatted file that contains a CA certificate to be used for validation. + - Only used if O(validate_certs=true). + type: path + ciphers: + required: false + description: + - TLS/SSL Ciphers to use for the request. + - When a list is provided, all ciphers are joined in order with V(:). + - See the L(OpenSSL Cipher List Format,https://www.openssl.org/docs/manmaster/man1/openssl-ciphers.html#CIPHER-LIST-FORMAT) + for more details. + - The available ciphers is dependent on the Python and OpenSSL/LibreSSL versions. + type: list + elements: str +""" diff --git a/plugins/module_utils/redfish_utils.py b/plugins/module_utils/redfish_utils.py index f4e8cd5a36..f7332aa99b 100644 --- a/plugins/module_utils/redfish_utils.py +++ b/plugins/module_utils/redfish_utils.py @@ -38,6 +38,21 @@ FAIL_MSG = 'Issuing a data modification command without specifying the '\ 'than one %(resource)s is no longer allowed. Use the `resource_id` '\ 'option to specify the target %(resource)s ID.' +# Use together with the community.general.redfish docs fragment +REDFISH_COMMON_ARGUMENT_SPEC = { + "validate_certs": { + "type": "bool", + "default": False, + }, + "ca_path": { + "type": "path", + }, + "ciphers": { + "type": "list", + "elements": "str", + }, +} + class RedfishUtils(object): @@ -53,8 +68,10 @@ class RedfishUtils(object): self.resource_id = resource_id self.data_modification = data_modification self.strip_etag_quotes = strip_etag_quotes - self.ciphers = ciphers + self.ciphers = ciphers if ciphers is not None else module.params.get("ciphers") self._vendor = None + self.validate_certs = module.params.get("validate_certs", False) + self.ca_path = module.params.get("ca_path") def _auth_params(self, headers): """ @@ -132,6 +149,17 @@ class RedfishUtils(object): resp['msg'] = 'Properties in %s are already set' % uri return resp + def _request(self, uri, **kwargs): + kwargs.setdefault("validate_certs", self.validate_certs) + kwargs.setdefault("follow_redirects", "all") + kwargs.setdefault("use_proxy", True) + kwargs.setdefault("timeout", self.timeout) + kwargs.setdefault("ciphers", self.ciphers) + kwargs.setdefault("ca_path", self.ca_path) + resp = open_url(uri, **kwargs) + headers = {k.lower(): v for (k, v) in resp.info().items()} + return resp, headers + # The following functions are to send GET/POST/PATCH/DELETE requests def get_request(self, uri, override_headers=None, allow_no_resp=False, timeout=None): req_headers = dict(GET_HEADERS) @@ -145,12 +173,15 @@ class RedfishUtils(object): # in case the caller will be using sessions later. if uri == (self.root_uri + self.service_root): basic_auth = False - resp = open_url(uri, method="GET", headers=req_headers, - url_username=username, url_password=password, - force_basic_auth=basic_auth, validate_certs=False, - follow_redirects='all', - use_proxy=True, timeout=timeout, ciphers=self.ciphers) - headers = {k.lower(): v for (k, v) in resp.info().items()} + resp, headers = self._request( + uri, + method="GET", + headers=req_headers, + url_username=username, + url_password=password, + force_basic_auth=basic_auth, + timeout=timeout, + ) try: if headers.get('content-encoding') == 'gzip' and LooseVersion(ansible_version) < LooseVersion('2.14'): # Older versions of Ansible do not automatically decompress the data @@ -194,18 +225,20 @@ class RedfishUtils(object): req_headers['content-type'] = multipart_encoder[1] else: data = json.dumps(pyld) - resp = open_url(uri, data=data, - headers=req_headers, method="POST", - url_username=username, url_password=password, - force_basic_auth=basic_auth, validate_certs=False, - follow_redirects='all', - use_proxy=True, timeout=self.timeout, ciphers=self.ciphers) + resp, headers = self._request( + uri, + data=data, + headers=req_headers, + method="POST", + url_username=username, + url_password=password, + force_basic_auth=basic_auth, + ) try: data = json.loads(to_native(resp.read())) except Exception as e: # No response data; this is okay in many cases data = None - headers = {k.lower(): v for (k, v) in resp.info().items()} except HTTPError as e: msg, data = self._get_extended_message(e) return {'ret': False, @@ -248,12 +281,15 @@ class RedfishUtils(object): username, password, basic_auth = self._auth_params(req_headers) try: - resp = open_url(uri, data=json.dumps(pyld), - headers=req_headers, method="PATCH", - url_username=username, url_password=password, - force_basic_auth=basic_auth, validate_certs=False, - follow_redirects='all', - use_proxy=True, timeout=self.timeout, ciphers=self.ciphers) + resp, dummy = self._request( + uri, + data=json.dumps(pyld), + headers=req_headers, + method="PATCH", + url_username=username, + url_password=password, + force_basic_auth=basic_auth, + ) except HTTPError as e: msg, data = self._get_extended_message(e) return {'ret': False, 'changed': False, @@ -283,12 +319,15 @@ class RedfishUtils(object): req_headers['If-Match'] = etag username, password, basic_auth = self._auth_params(req_headers) try: - resp = open_url(uri, data=json.dumps(pyld), - headers=req_headers, method="PUT", - url_username=username, url_password=password, - force_basic_auth=basic_auth, validate_certs=False, - follow_redirects='all', - use_proxy=True, timeout=self.timeout, ciphers=self.ciphers) + resp, dummy = self._request( + uri, + data=json.dumps(pyld), + headers=req_headers, + method="PUT", + url_username=username, + url_password=password, + force_basic_auth=basic_auth, + ) except HTTPError as e: msg, data = self._get_extended_message(e) return {'ret': False, @@ -309,12 +348,15 @@ class RedfishUtils(object): username, password, basic_auth = self._auth_params(req_headers) try: data = json.dumps(pyld) if pyld else None - resp = open_url(uri, data=data, - headers=req_headers, method="DELETE", - url_username=username, url_password=password, - force_basic_auth=basic_auth, validate_certs=False, - follow_redirects='all', - use_proxy=True, timeout=self.timeout, ciphers=self.ciphers) + resp, dummy = self._request( + uri, + data=data, + headers=req_headers, + method="DELETE", + url_username=username, + url_password=password, + force_basic_auth=basic_auth, + ) except HTTPError as e: msg, data = self._get_extended_message(e) return {'ret': False, diff --git a/plugins/modules/idrac_redfish_command.py b/plugins/modules/idrac_redfish_command.py index 531da53162..fa4f29e5f5 100644 --- a/plugins/modules/idrac_redfish_command.py +++ b/plugins/modules/idrac_redfish_command.py @@ -16,6 +16,7 @@ description: - For use with Dell iDRAC operations that require Redfish OEM extensions. extends_documentation_fragment: - community.general.attributes + - community.general.redfish attributes: check_mode: support: none @@ -62,6 +63,12 @@ options: - ID of the System, Manager or Chassis to modify. type: str version_added: '0.2.0' + validate_certs: + version_added: 10.6.0 + ca_path: + version_added: 10.6.0 + ciphers: + version_added: 10.6.0 author: "Jose Delarosa (@jose-delarosa)" """ @@ -93,7 +100,7 @@ return_values: import re from ansible.module_utils.basic import AnsibleModule -from ansible_collections.community.general.plugins.module_utils.redfish_utils import RedfishUtils +from ansible_collections.community.general.plugins.module_utils.redfish_utils import RedfishUtils, REDFISH_COMMON_ARGUMENT_SPEC from ansible.module_utils.common.text.converters import to_native @@ -147,17 +154,19 @@ CATEGORY_COMMANDS_ALL = { def main(): result = {} return_values = {} + argument_spec = dict( + category=dict(required=True), + command=dict(required=True, type='list', elements='str'), + baseuri=dict(required=True), + username=dict(), + password=dict(no_log=True), + auth_token=dict(no_log=True), + timeout=dict(type='int', default=10), + resource_id=dict() + ) + argument_spec.update(REDFISH_COMMON_ARGUMENT_SPEC) module = AnsibleModule( - argument_spec=dict( - category=dict(required=True), - command=dict(required=True, type='list', elements='str'), - baseuri=dict(required=True), - username=dict(), - password=dict(no_log=True), - auth_token=dict(no_log=True), - timeout=dict(type='int', default=10), - resource_id=dict() - ), + argument_spec, required_together=[ ('username', 'password'), ], diff --git a/plugins/modules/idrac_redfish_config.py b/plugins/modules/idrac_redfish_config.py index 97d7a62d04..466e0b344c 100644 --- a/plugins/modules/idrac_redfish_config.py +++ b/plugins/modules/idrac_redfish_config.py @@ -16,6 +16,7 @@ description: - Builds Redfish URIs locally and sends them to remote iDRAC controllers to set or update a configuration attribute. extends_documentation_fragment: - community.general.attributes + - community.general.redfish attributes: check_mode: support: none @@ -71,6 +72,12 @@ options: - ID of the System, Manager or Chassis to modify. type: str version_added: '0.2.0' + validate_certs: + version_added: 10.6.0 + ca_path: + version_added: 10.6.0 + ciphers: + version_added: 10.6.0 author: "Jose Delarosa (@jose-delarosa)" """ @@ -154,7 +161,7 @@ from ansible.module_utils.common.validation import ( check_mutually_exclusive, check_required_arguments ) -from ansible_collections.community.general.plugins.module_utils.redfish_utils import RedfishUtils +from ansible_collections.community.general.plugins.module_utils.redfish_utils import RedfishUtils, REDFISH_COMMON_ARGUMENT_SPEC from ansible.module_utils.common.text.converters import to_native @@ -246,18 +253,20 @@ CATEGORY_COMMANDS_MUTUALLY_EXCLUSIVE = { def main(): result = {} + argument_spec = dict( + category=dict(required=True), + command=dict(required=True, type='list', elements='str'), + baseuri=dict(required=True), + username=dict(), + password=dict(no_log=True), + auth_token=dict(no_log=True), + manager_attributes=dict(type='dict', default={}), + timeout=dict(type='int', default=10), + resource_id=dict() + ) + argument_spec.update(REDFISH_COMMON_ARGUMENT_SPEC) module = AnsibleModule( - argument_spec=dict( - category=dict(required=True), - command=dict(required=True, type='list', elements='str'), - baseuri=dict(required=True), - username=dict(), - password=dict(no_log=True), - auth_token=dict(no_log=True), - manager_attributes=dict(type='dict', default={}), - timeout=dict(type='int', default=10), - resource_id=dict() - ), + argument_spec, required_together=[ ('username', 'password'), ], diff --git a/plugins/modules/idrac_redfish_info.py b/plugins/modules/idrac_redfish_info.py index 3a8ea8103f..4b9745f7c2 100644 --- a/plugins/modules/idrac_redfish_info.py +++ b/plugins/modules/idrac_redfish_info.py @@ -17,6 +17,7 @@ description: extends_documentation_fragment: - community.general.attributes - community.general.attributes.info_module + - community.general.redfish attributes: check_mode: version_added: 3.3.0 @@ -57,6 +58,12 @@ options: - Timeout in seconds for HTTP requests to iDRAC. default: 10 type: int + validate_certs: + version_added: 10.6.0 + ca_path: + version_added: 10.6.0 + ciphers: + version_added: 10.6.0 author: "Jose Delarosa (@jose-delarosa)" """ @@ -124,7 +131,7 @@ msg: """ from ansible.module_utils.basic import AnsibleModule -from ansible_collections.community.general.plugins.module_utils.redfish_utils import RedfishUtils +from ansible_collections.community.general.plugins.module_utils.redfish_utils import RedfishUtils, REDFISH_COMMON_ARGUMENT_SPEC from ansible.module_utils.common.text.converters import to_native @@ -177,16 +184,18 @@ CATEGORY_COMMANDS_ALL = { def main(): result = {} + argument_spec = dict( + category=dict(required=True), + command=dict(required=True, type='list', elements='str'), + baseuri=dict(required=True), + username=dict(), + password=dict(no_log=True), + auth_token=dict(no_log=True), + timeout=dict(type='int', default=10) + ) + argument_spec.update(REDFISH_COMMON_ARGUMENT_SPEC) module = AnsibleModule( - argument_spec=dict( - category=dict(required=True), - command=dict(required=True, type='list', elements='str'), - baseuri=dict(required=True), - username=dict(), - password=dict(no_log=True), - auth_token=dict(no_log=True), - timeout=dict(type='int', default=10) - ), + argument_spec, required_together=[ ('username', 'password'), ], diff --git a/plugins/modules/ilo_redfish_command.py b/plugins/modules/ilo_redfish_command.py index 3e698fc049..52b08f8654 100644 --- a/plugins/modules/ilo_redfish_command.py +++ b/plugins/modules/ilo_redfish_command.py @@ -19,6 +19,7 @@ attributes: support: none extends_documentation_fragment: - community.general.attributes + - community.general.redfish options: category: required: true @@ -58,6 +59,12 @@ options: - Timeout in seconds for HTTP requests to iLO. default: 60 type: int + validate_certs: + version_added: 10.6.0 + ca_path: + version_added: 10.6.0 + ciphers: + version_added: 10.6.0 author: - Varni H P (@varini-hp) """ @@ -96,22 +103,25 @@ CATEGORY_COMMANDS_ALL = { } from ansible_collections.community.general.plugins.module_utils.ilo_redfish_utils import iLORedfishUtils +from ansible_collections.community.general.plugins.module_utils.redfish_utils import REDFISH_COMMON_ARGUMENT_SPEC from ansible.module_utils.basic import AnsibleModule from ansible.module_utils.common.text.converters import to_native def main(): result = {} + argument_spec = dict( + category=dict(required=True, choices=list(CATEGORY_COMMANDS_ALL.keys())), + command=dict(required=True, type='list', elements='str'), + baseuri=dict(required=True), + timeout=dict(type="int", default=60), + username=dict(), + password=dict(no_log=True), + auth_token=dict(no_log=True) + ) + argument_spec.update(REDFISH_COMMON_ARGUMENT_SPEC) module = AnsibleModule( - argument_spec=dict( - category=dict(required=True, choices=list(CATEGORY_COMMANDS_ALL.keys())), - command=dict(required=True, type='list', elements='str'), - baseuri=dict(required=True), - timeout=dict(type="int", default=60), - username=dict(), - password=dict(no_log=True), - auth_token=dict(no_log=True) - ), + argument_spec, required_together=[ ('username', 'password'), ], diff --git a/plugins/modules/ilo_redfish_config.py b/plugins/modules/ilo_redfish_config.py index fdda339ab3..95c45590e1 100644 --- a/plugins/modules/ilo_redfish_config.py +++ b/plugins/modules/ilo_redfish_config.py @@ -15,6 +15,7 @@ description: - For use with HPE iLO operations that require Redfish OEM extensions. extends_documentation_fragment: - community.general.attributes + - community.general.redfish attributes: check_mode: support: none @@ -65,6 +66,12 @@ options: description: - Value of the attribute to be configured. type: str + validate_certs: + version_added: 10.6.0 + ca_path: + version_added: 10.6.0 + ciphers: + version_added: 10.6.0 author: - "Bhavya B (@bhavya06)" """ @@ -113,25 +120,28 @@ CATEGORY_COMMANDS_ALL = { } from ansible_collections.community.general.plugins.module_utils.ilo_redfish_utils import iLORedfishUtils +from ansible_collections.community.general.plugins.module_utils.redfish_utils import REDFISH_COMMON_ARGUMENT_SPEC from ansible.module_utils.basic import AnsibleModule from ansible.module_utils.common.text.converters import to_native def main(): result = {} + argument_spec = dict( + category=dict(required=True, choices=list( + CATEGORY_COMMANDS_ALL.keys())), + command=dict(required=True, type='list', elements='str'), + baseuri=dict(required=True), + username=dict(), + password=dict(no_log=True), + auth_token=dict(no_log=True), + attribute_name=dict(required=True), + attribute_value=dict(type='str'), + timeout=dict(type='int', default=10) + ) + argument_spec.update(REDFISH_COMMON_ARGUMENT_SPEC) module = AnsibleModule( - argument_spec=dict( - category=dict(required=True, choices=list( - CATEGORY_COMMANDS_ALL.keys())), - command=dict(required=True, type='list', elements='str'), - baseuri=dict(required=True), - username=dict(), - password=dict(no_log=True), - auth_token=dict(no_log=True), - attribute_name=dict(required=True), - attribute_value=dict(type='str'), - timeout=dict(type='int', default=10) - ), + argument_spec, required_together=[ ('username', 'password'), ], diff --git a/plugins/modules/ilo_redfish_info.py b/plugins/modules/ilo_redfish_info.py index 3bd379e80a..daa43b004e 100644 --- a/plugins/modules/ilo_redfish_info.py +++ b/plugins/modules/ilo_redfish_info.py @@ -16,6 +16,7 @@ description: extends_documentation_fragment: - community.general.attributes - community.general.attributes.info_module + - community.general.redfish options: category: required: true @@ -51,6 +52,12 @@ options: - Timeout in seconds for HTTP requests to iLO. default: 10 type: int + validate_certs: + version_added: 10.6.0 + ca_path: + version_added: 10.6.0 + ciphers: + version_added: 10.6.0 author: - "Bhavya B (@bhavya06)" """ @@ -108,21 +115,24 @@ CATEGORY_COMMANDS_DEFAULT = { from ansible.module_utils.basic import AnsibleModule from ansible_collections.community.general.plugins.module_utils.ilo_redfish_utils import iLORedfishUtils +from ansible_collections.community.general.plugins.module_utils.redfish_utils import REDFISH_COMMON_ARGUMENT_SPEC def main(): result = {} category_list = [] + argument_spec = dict( + category=dict(required=True, type='list', elements='str'), + command=dict(required=True, type='list', elements='str'), + baseuri=dict(required=True), + username=dict(), + password=dict(no_log=True), + auth_token=dict(no_log=True), + timeout=dict(type='int', default=10) + ) + argument_spec.update(REDFISH_COMMON_ARGUMENT_SPEC) module = AnsibleModule( - argument_spec=dict( - category=dict(required=True, type='list', elements='str'), - command=dict(required=True, type='list', elements='str'), - baseuri=dict(required=True), - username=dict(), - password=dict(no_log=True), - auth_token=dict(no_log=True), - timeout=dict(type='int', default=10) - ), + argument_spec, required_together=[ ('username', 'password'), ], diff --git a/plugins/modules/redfish_command.py b/plugins/modules/redfish_command.py index 545506f924..25f92bd1f7 100644 --- a/plugins/modules/redfish_command.py +++ b/plugins/modules/redfish_command.py @@ -18,6 +18,7 @@ description: - Manages system power ex. on, off, graceful and forced reboot. extends_documentation_fragment: - community.general.attributes + - community.general.redfish attributes: check_mode: support: none @@ -324,16 +325,11 @@ options: default: 120 version_added: 9.1.0 ciphers: - required: false - description: - - SSL/TLS Ciphers to use for the request. - - When a list is provided, all ciphers are joined in order with V(:). - - See the L(OpenSSL Cipher List Format,https://www.openssl.org/docs/manmaster/man1/openssl-ciphers.html#CIPHER-LIST-FORMAT) - for more details. - - The available ciphers is dependent on the Python and OpenSSL/LibreSSL versions. - type: list - elements: str version_added: 9.2.0 + validate_certs: + version_added: 10.6.0 + ca_path: + version_added: 10.6.0 author: - "Jose Delarosa (@jose-delarosa)" @@ -846,7 +842,7 @@ return_values: """ from ansible.module_utils.basic import AnsibleModule -from ansible_collections.community.general.plugins.module_utils.redfish_utils import RedfishUtils +from ansible_collections.community.general.plugins.module_utils.redfish_utils import RedfishUtils, REDFISH_COMMON_ARGUMENT_SPEC from ansible.module_utils.common.text.converters import to_native @@ -873,67 +869,68 @@ CATEGORY_COMMANDS_ALL = { def main(): result = {} return_values = {} - module = AnsibleModule( - argument_spec=dict( - category=dict(required=True), - command=dict(required=True, type='list', elements='str'), - baseuri=dict(required=True), - username=dict(), - password=dict(no_log=True), - auth_token=dict(no_log=True), - session_uri=dict(), - id=dict(aliases=["account_id"]), - new_username=dict(aliases=["account_username"]), - new_password=dict(aliases=["account_password"], no_log=True), - roleid=dict(aliases=["account_roleid"]), - account_types=dict(type='list', elements='str', aliases=["account_accounttypes"]), - oem_account_types=dict(type='list', elements='str', aliases=["account_oemaccounttypes"]), - update_username=dict(type='str', aliases=["account_updatename"]), - account_properties=dict(type='dict', default={}), - bootdevice=dict(), - timeout=dict(type='int', default=60), - uefi_target=dict(), - boot_next=dict(), - boot_override_mode=dict(choices=['Legacy', 'UEFI']), - resource_id=dict(), - update_image_uri=dict(), - update_image_file=dict(type='path'), - update_protocol=dict(), - update_targets=dict(type='list', elements='str', default=[]), - update_oem_params=dict(type='dict'), - update_custom_oem_header=dict(type='str'), - update_custom_oem_mime_type=dict(type='str'), - update_custom_oem_params=dict(type='raw'), - update_creds=dict( - type='dict', - options=dict( - username=dict(), - password=dict(no_log=True) - ) - ), - update_apply_time=dict(choices=['Immediate', 'OnReset', 'AtMaintenanceWindowStart', - 'InMaintenanceWindowOnReset', 'OnStartUpdateRequest']), - update_handle=dict(), - virtual_media=dict( - type='dict', - options=dict( - media_types=dict(type='list', elements='str', default=[]), - image_url=dict(), - inserted=dict(type='bool', default=True), - write_protected=dict(type='bool', default=True), - username=dict(), - password=dict(no_log=True), - transfer_protocol_type=dict(), - transfer_method=dict(), - ) - ), - strip_etag_quotes=dict(type='bool', default=False), - reset_to_defaults_mode=dict(choices=['ResetAll', 'PreserveNetworkAndUsers', 'PreserveNetwork']), - bios_attributes=dict(type="dict"), - wait=dict(type='bool', default=False), - wait_timeout=dict(type='int', default=120), - ciphers=dict(type='list', elements='str'), + argument_spec = dict( + category=dict(required=True), + command=dict(required=True, type='list', elements='str'), + baseuri=dict(required=True), + username=dict(), + password=dict(no_log=True), + auth_token=dict(no_log=True), + session_uri=dict(), + id=dict(aliases=["account_id"]), + new_username=dict(aliases=["account_username"]), + new_password=dict(aliases=["account_password"], no_log=True), + roleid=dict(aliases=["account_roleid"]), + account_types=dict(type='list', elements='str', aliases=["account_accounttypes"]), + oem_account_types=dict(type='list', elements='str', aliases=["account_oemaccounttypes"]), + update_username=dict(type='str', aliases=["account_updatename"]), + account_properties=dict(type='dict', default={}), + bootdevice=dict(), + timeout=dict(type='int', default=60), + uefi_target=dict(), + boot_next=dict(), + boot_override_mode=dict(choices=['Legacy', 'UEFI']), + resource_id=dict(), + update_image_uri=dict(), + update_image_file=dict(type='path'), + update_protocol=dict(), + update_targets=dict(type='list', elements='str', default=[]), + update_oem_params=dict(type='dict'), + update_custom_oem_header=dict(type='str'), + update_custom_oem_mime_type=dict(type='str'), + update_custom_oem_params=dict(type='raw'), + update_creds=dict( + type='dict', + options=dict( + username=dict(), + password=dict(no_log=True) + ) ), + update_apply_time=dict(choices=['Immediate', 'OnReset', 'AtMaintenanceWindowStart', + 'InMaintenanceWindowOnReset', 'OnStartUpdateRequest']), + update_handle=dict(), + virtual_media=dict( + type='dict', + options=dict( + media_types=dict(type='list', elements='str', default=[]), + image_url=dict(), + inserted=dict(type='bool', default=True), + write_protected=dict(type='bool', default=True), + username=dict(), + password=dict(no_log=True), + transfer_protocol_type=dict(), + transfer_method=dict(), + ) + ), + strip_etag_quotes=dict(type='bool', default=False), + reset_to_defaults_mode=dict(choices=['ResetAll', 'PreserveNetworkAndUsers', 'PreserveNetwork']), + bios_attributes=dict(type="dict"), + wait=dict(type='bool', default=False), + wait_timeout=dict(type='int', default=120), + ) + argument_spec.update(REDFISH_COMMON_ARGUMENT_SPEC) + module = AnsibleModule( + argument_spec, required_together=[ ('username', 'password'), ('update_custom_oem_header', 'update_custom_oem_params'), @@ -1006,14 +1003,10 @@ def main(): # BIOS Attributes options bios_attributes = module.params['bios_attributes'] - # ciphers - ciphers = module.params['ciphers'] - # Build root URI root_uri = "https://" + module.params['baseuri'] rf_utils = RedfishUtils(creds, root_uri, timeout, module, - resource_id=resource_id, data_modification=True, strip_etag_quotes=strip_etag_quotes, - ciphers=ciphers) + resource_id=resource_id, data_modification=True, strip_etag_quotes=strip_etag_quotes) # Check that Category is valid if category not in CATEGORY_COMMANDS_ALL: diff --git a/plugins/modules/redfish_config.py b/plugins/modules/redfish_config.py index 817cc18787..8700d4b8de 100644 --- a/plugins/modules/redfish_config.py +++ b/plugins/modules/redfish_config.py @@ -17,6 +17,7 @@ description: - Manages OOB controller configuration settings. extends_documentation_fragment: - community.general.attributes + - community.general.redfish attributes: check_mode: support: none @@ -181,16 +182,11 @@ options: - LastState version_added: '10.5.0' ciphers: - required: false - description: - - SSL/TLS Ciphers to use for the request. - - When a list is provided, all ciphers are joined in order with V(:). - - See the L(OpenSSL Cipher List Format,https://www.openssl.org/docs/manmaster/man1/openssl-ciphers.html#CIPHER-LIST-FORMAT) - for more details. - - The available ciphers is dependent on the Python and OpenSSL/LibreSSL versions. - type: list - elements: str version_added: 9.2.0 + validate_certs: + version_added: 10.6.0 + ca_path: + version_added: 10.6.0 author: - "Jose Delarosa (@jose-delarosa)" @@ -395,7 +391,7 @@ msg: """ from ansible.module_utils.basic import AnsibleModule -from ansible_collections.community.general.plugins.module_utils.redfish_utils import RedfishUtils +from ansible_collections.community.general.plugins.module_utils.redfish_utils import RedfishUtils, REDFISH_COMMON_ARGUMENT_SPEC from ansible.module_utils.common.text.converters import to_native @@ -411,40 +407,41 @@ CATEGORY_COMMANDS_ALL = { def main(): result = {} - module = AnsibleModule( - argument_spec=dict( - category=dict(required=True), - command=dict(required=True, type='list', elements='str'), - baseuri=dict(required=True), - username=dict(), - password=dict(no_log=True), - auth_token=dict(no_log=True), - bios_attributes=dict(type='dict', default={}), - timeout=dict(type='int', default=60), - boot_order=dict(type='list', elements='str', default=[]), - network_protocols=dict( - type='dict', - default={} - ), - resource_id=dict(), - service_id=dict(), - nic_addr=dict(default='null'), - nic_config=dict( - type='dict', - default={} - ), - strip_etag_quotes=dict(type='bool', default=False), - hostinterface_config=dict(type='dict', default={}), - hostinterface_id=dict(), - sessions_config=dict(type='dict', default={}), - storage_subsystem_id=dict(type='str', default=''), - storage_none_volume_deletion=dict(type='bool', default=False), - volume_ids=dict(type='list', default=[], elements='str'), - secure_boot_enable=dict(type='bool', default=True), - volume_details=dict(type='dict', default={}), - power_restore_policy=dict(choices=['AlwaysOn', 'AlwaysOff', 'LastState']), - ciphers=dict(type='list', elements='str'), + argument_spec = dict( + category=dict(required=True), + command=dict(required=True, type='list', elements='str'), + baseuri=dict(required=True), + username=dict(), + password=dict(no_log=True), + auth_token=dict(no_log=True), + bios_attributes=dict(type='dict', default={}), + timeout=dict(type='int', default=60), + boot_order=dict(type='list', elements='str', default=[]), + network_protocols=dict( + type='dict', + default={} ), + resource_id=dict(), + service_id=dict(), + nic_addr=dict(default='null'), + nic_config=dict( + type='dict', + default={} + ), + strip_etag_quotes=dict(type='bool', default=False), + hostinterface_config=dict(type='dict', default={}), + hostinterface_id=dict(), + sessions_config=dict(type='dict', default={}), + storage_subsystem_id=dict(type='str', default=''), + storage_none_volume_deletion=dict(type='bool', default=False), + volume_ids=dict(type='list', default=[], elements='str'), + secure_boot_enable=dict(type='bool', default=True), + volume_details=dict(type='dict', default={}), + power_restore_policy=dict(choices=['AlwaysOn', 'AlwaysOff', 'LastState']), + ) + argument_spec.update(REDFISH_COMMON_ARGUMENT_SPEC) + module = AnsibleModule( + argument_spec, required_together=[ ('username', 'password'), ], @@ -511,14 +508,10 @@ def main(): # Power Restore Policy power_restore_policy = module.params['power_restore_policy'] - # ciphers - ciphers = module.params['ciphers'] - # Build root URI root_uri = "https://" + module.params['baseuri'] rf_utils = RedfishUtils(creds, root_uri, timeout, module, - resource_id=resource_id, data_modification=True, strip_etag_quotes=strip_etag_quotes, - ciphers=ciphers) + resource_id=resource_id, data_modification=True, strip_etag_quotes=strip_etag_quotes) # Check that Category is valid if category not in CATEGORY_COMMANDS_ALL: diff --git a/plugins/modules/redfish_info.py b/plugins/modules/redfish_info.py index 66d41883e5..fb87bef8c6 100644 --- a/plugins/modules/redfish_info.py +++ b/plugins/modules/redfish_info.py @@ -17,6 +17,7 @@ description: extends_documentation_fragment: - community.general.attributes - community.general.attributes.info_module + - community.general.redfish attributes: check_mode: version_added: 3.3.0 @@ -71,16 +72,11 @@ options: type: str version_added: '6.1.0' ciphers: - required: false - description: - - SSL/TLS Ciphers to use for the request. - - When a list is provided, all ciphers are joined in order with V(:). - - See the L(OpenSSL Cipher List Format,https://www.openssl.org/docs/manmaster/man1/openssl-ciphers.html#CIPHER-LIST-FORMAT) - for more details. - - The available ciphers is dependent on the Python and OpenSSL/LibreSSL versions. - type: list - elements: str version_added: 9.2.0 + validate_certs: + version_added: 10.6.0 + ca_path: + version_added: 10.6.0 author: "Jose Delarosa (@jose-delarosa)" """ @@ -404,7 +400,7 @@ result: """ from ansible.module_utils.basic import AnsibleModule -from ansible_collections.community.general.plugins.module_utils.redfish_utils import RedfishUtils +from ansible_collections.community.general.plugins.module_utils.redfish_utils import RedfishUtils, REDFISH_COMMON_ARGUMENT_SPEC CATEGORY_COMMANDS_ALL = { "Systems": ["GetSystemInventory", "GetPsuInventory", "GetCpuInventory", @@ -437,19 +433,20 @@ CATEGORY_COMMANDS_DEFAULT = { def main(): result = {} category_list = [] + argument_spec = dict( + category=dict(type='list', elements='str', default=['Systems']), + command=dict(type='list', elements='str'), + baseuri=dict(required=True), + username=dict(), + password=dict(no_log=True), + auth_token=dict(no_log=True), + timeout=dict(type='int', default=60), + update_handle=dict(), + manager=dict(), + ) + argument_spec.update(REDFISH_COMMON_ARGUMENT_SPEC) module = AnsibleModule( - argument_spec=dict( - category=dict(type='list', elements='str', default=['Systems']), - command=dict(type='list', elements='str'), - baseuri=dict(required=True), - username=dict(), - password=dict(no_log=True), - auth_token=dict(no_log=True), - timeout=dict(type='int', default=60), - update_handle=dict(), - manager=dict(), - ciphers=dict(type='list', elements='str'), - ), + argument_spec, required_together=[ ('username', 'password'), ], @@ -476,12 +473,9 @@ def main(): # manager manager = module.params['manager'] - # ciphers - ciphers = module.params['ciphers'] - # Build root URI root_uri = "https://" + module.params['baseuri'] - rf_utils = RedfishUtils(creds, root_uri, timeout, module, ciphers=ciphers) + rf_utils = RedfishUtils(creds, root_uri, timeout, module) # Build Category list if "all" in module.params['category']: diff --git a/plugins/modules/wdc_redfish_command.py b/plugins/modules/wdc_redfish_command.py index 680bd4b3f9..20afa8add1 100644 --- a/plugins/modules/wdc_redfish_command.py +++ b/plugins/modules/wdc_redfish_command.py @@ -17,6 +17,7 @@ description: - Manages OOB controller firmware. For example, Firmware Activate, Update and Activate. extends_documentation_fragment: - community.general.attributes + - community.general.redfish attributes: check_mode: support: full @@ -87,6 +88,12 @@ options: description: - The password for retrieving the update image. type: str + validate_certs: + version_added: 10.6.0 + ca_path: + version_added: 10.6.0 + ciphers: + version_added: 10.6.0 notes: - In the inventory, you can specify baseuri or ioms. See the EXAMPLES section. - Ioms is a list of FQDNs for the enclosure's IOMs. @@ -195,6 +202,7 @@ msg: """ from ansible_collections.community.general.plugins.module_utils.wdc_redfish_utils import WdcRedfishUtils +from ansible_collections.community.general.plugins.module_utils.redfish_utils import REDFISH_COMMON_ARGUMENT_SPEC from ansible.module_utils.basic import AnsibleModule from ansible.module_utils.common.text.converters import to_native @@ -213,26 +221,28 @@ CATEGORY_COMMANDS_ALL = { def main(): - module = AnsibleModule( - argument_spec=dict( - category=dict(required=True), - command=dict(required=True, type='list', elements='str'), - ioms=dict(type='list', elements='str'), - baseuri=dict(), - username=dict(), - password=dict(no_log=True), - auth_token=dict(no_log=True), - update_creds=dict( - type='dict', - options=dict( - username=dict(), - password=dict(no_log=True) - ) - ), - resource_id=dict(), - update_image_uri=dict(), - timeout=dict(type='int', default=10) + argument_spec = dict( + category=dict(required=True), + command=dict(required=True, type='list', elements='str'), + ioms=dict(type='list', elements='str'), + baseuri=dict(), + username=dict(), + password=dict(no_log=True), + auth_token=dict(no_log=True), + update_creds=dict( + type='dict', + options=dict( + username=dict(), + password=dict(no_log=True) + ) ), + resource_id=dict(), + update_image_uri=dict(), + timeout=dict(type='int', default=10) + ) + argument_spec.update(REDFISH_COMMON_ARGUMENT_SPEC) + module = AnsibleModule( + argument_spec, required_together=[ ('username', 'password'), ], diff --git a/plugins/modules/wdc_redfish_info.py b/plugins/modules/wdc_redfish_info.py index caaa9c7fd9..19a513c00d 100644 --- a/plugins/modules/wdc_redfish_info.py +++ b/plugins/modules/wdc_redfish_info.py @@ -17,6 +17,7 @@ description: extends_documentation_fragment: - community.general.attributes - community.general.attributes.info_module + - community.general.redfish options: category: required: true @@ -55,6 +56,12 @@ options: - Timeout in seconds for URL requests to OOB controller. default: 10 type: int + validate_certs: + version_added: 10.6.0 + ca_path: + version_added: 10.6.0 + ciphers: + version_added: 10.6.0 notes: - In the inventory, you can specify baseuri or ioms. See the EXAMPLES section. @@ -118,6 +125,7 @@ StatusCode: from ansible.module_utils.basic import AnsibleModule from ansible.module_utils.common.text.converters import to_native from ansible_collections.community.general.plugins.module_utils.wdc_redfish_utils import WdcRedfishUtils +from ansible_collections.community.general.plugins.module_utils.redfish_utils import REDFISH_COMMON_ARGUMENT_SPEC CATEGORY_COMMANDS_ALL = { "Update": ["SimpleUpdateStatus"] @@ -126,17 +134,19 @@ CATEGORY_COMMANDS_ALL = { def main(): result = {} + argument_spec = dict( + category=dict(required=True), + command=dict(required=True, type='list', elements='str'), + ioms=dict(type='list', elements='str'), + baseuri=dict(), + username=dict(), + password=dict(no_log=True), + auth_token=dict(no_log=True), + timeout=dict(type='int', default=10) + ) + argument_spec.update(REDFISH_COMMON_ARGUMENT_SPEC) module = AnsibleModule( - argument_spec=dict( - category=dict(required=True), - command=dict(required=True, type='list', elements='str'), - ioms=dict(type='list', elements='str'), - baseuri=dict(), - username=dict(), - password=dict(no_log=True), - auth_token=dict(no_log=True), - timeout=dict(type='int', default=10) - ), + argument_spec, required_together=[ ('username', 'password'), ], diff --git a/plugins/modules/xcc_redfish_command.py b/plugins/modules/xcc_redfish_command.py index 509c70e4e9..8e5cbf7d3e 100644 --- a/plugins/modules/xcc_redfish_command.py +++ b/plugins/modules/xcc_redfish_command.py @@ -21,6 +21,7 @@ description: - Supports performing an action using POST method. extends_documentation_fragment: - community.general.attributes + - community.general.redfish attributes: check_mode: support: none @@ -117,6 +118,12 @@ options: description: - The request body to patch or post. type: dict + validate_certs: + version_added: 10.6.0 + ca_path: + version_added: 10.6.0 + ciphers: + version_added: 10.6.0 author: "Yuyan Pan (@panyy3)" """ @@ -297,7 +304,7 @@ redfish_facts: from ansible.module_utils.basic import AnsibleModule from ansible.module_utils.common.text.converters import to_native -from ansible_collections.community.general.plugins.module_utils.redfish_utils import RedfishUtils +from ansible_collections.community.general.plugins.module_utils.redfish_utils import RedfishUtils, REDFISH_COMMON_ARGUMENT_SPEC class XCCRedfishUtils(RedfishUtils): @@ -678,34 +685,36 @@ CATEGORY_COMMANDS_ALL = { def main(): result = {} - module = AnsibleModule( - argument_spec=dict( - category=dict(required=True), - command=dict(required=True, type='list', elements='str'), - baseuri=dict(required=True), - username=dict(), - password=dict(no_log=True), - auth_token=dict(no_log=True), - timeout=dict(type='int', default=10), - resource_id=dict(), - virtual_media=dict( - type='dict', - options=dict( - media_types=dict(type='list', elements='str', default=[]), - image_url=dict(), - inserted=dict(type='bool', default=True), - write_protected=dict(type='bool', default=True), - username=dict(), - password=dict(no_log=True), - transfer_protocol_type=dict(), - transfer_method=dict(), - ) - ), - resource_uri=dict(), - request_body=dict( - type='dict', - ), + argument_spec = dict( + category=dict(required=True), + command=dict(required=True, type='list', elements='str'), + baseuri=dict(required=True), + username=dict(), + password=dict(no_log=True), + auth_token=dict(no_log=True), + timeout=dict(type='int', default=10), + resource_id=dict(), + virtual_media=dict( + type='dict', + options=dict( + media_types=dict(type='list', elements='str', default=[]), + image_url=dict(), + inserted=dict(type='bool', default=True), + write_protected=dict(type='bool', default=True), + username=dict(), + password=dict(no_log=True), + transfer_protocol_type=dict(), + transfer_method=dict(), + ) ), + resource_uri=dict(), + request_body=dict( + type='dict', + ), + ) + argument_spec.update(REDFISH_COMMON_ARGUMENT_SPEC) + module = AnsibleModule( + argument_spec, required_together=[ ('username', 'password'), ],