From 6f47ddc29fa689803138288be68e461478006b3c Mon Sep 17 00:00:00 2001 From: Jacob Date: Sat, 13 Nov 2021 07:59:29 -0500 Subject: [PATCH] redfish_config: Add support to configure Redfish Host Interface (#3632) * redfish_config: Add support to configure Redfish Host Interface Adding another Manager command to redfish_config in order to set Redfish Host Interface properties. Fixes #3631 * add fragment * fixup for fragment filename * Update plugins/modules/remote_management/redfish/redfish_config.py Co-authored-by: Felix Fontein * Add support for specifying HostInterface resource ID * Apply suggestions from code review Co-authored-by: Felix Fontein * Update plugins/modules/remote_management/redfish/redfish_config.py Co-authored-by: Felix Fontein * Update changelogs/fragments/3632-add-redfish-host-interface-config-support.yml Co-authored-by: Felix Fontein Co-authored-by: Felix Fontein --- ...-redfish-host-interface-config-support.yml | 2 + plugins/module_utils/redfish_utils.py | 84 +++++++++++++++++++ .../redfish/redfish_config.py | 45 +++++++++- 3 files changed, 130 insertions(+), 1 deletion(-) create mode 100644 changelogs/fragments/3632-add-redfish-host-interface-config-support.yml diff --git a/changelogs/fragments/3632-add-redfish-host-interface-config-support.yml b/changelogs/fragments/3632-add-redfish-host-interface-config-support.yml new file mode 100644 index 0000000000..15017b6d1c --- /dev/null +++ b/changelogs/fragments/3632-add-redfish-host-interface-config-support.yml @@ -0,0 +1,2 @@ +minor_changes: + - redfish_command - add ``SetHostInterface`` command to enable configuring the Redfish Host Interface (https://github.com/ansible-collections/community.general/issues/3632). diff --git a/plugins/module_utils/redfish_utils.py b/plugins/module_utils/redfish_utils.py index c2f17e03fb..c432b7b0e3 100644 --- a/plugins/module_utils/redfish_utils.py +++ b/plugins/module_utils/redfish_utils.py @@ -2792,3 +2792,87 @@ class RedfishUtils(object): if response['ret'] is False: return response return {'ret': True, 'changed': True, 'msg': "Modified Manager NIC"} + + def set_hostinterface_attributes(self, hostinterface_config, hostinterface_id=None): + response = self.get_request(self.root_uri + self.manager_uri) + if response['ret'] is False: + return response + data = response['data'] + if 'HostInterfaces' not in data: + return {'ret': False, 'msg': "HostInterfaces resource not found"} + + hostinterfaces_uri = data["HostInterfaces"]["@odata.id"] + response = self.get_request(self.root_uri + hostinterfaces_uri) + if response['ret'] is False: + return response + data = response['data'] + uris = [a.get('@odata.id') for a in data.get('Members', []) if a.get('@odata.id')] + # Capture list of URIs that match a specified HostInterface resource ID + if hostinterface_id: + matching_hostinterface_uris = [uri for uri in uris if hostinterface_id in uri.split('/')[-1]] + + if hostinterface_id and matching_hostinterface_uris: + hostinterface_uri = list.pop(matching_hostinterface_uris) + elif hostinterface_id and not matching_hostinterface_uris: + return {'ret': False, 'msg': "HostInterface ID %s not present." % hostinterface_id} + elif len(uris) == 1: + hostinterface_uri = list.pop(uris) + else: + return {'ret': False, 'msg': "HostInterface ID not defined and multiple interfaces detected."} + + response = self.get_request(self.root_uri + hostinterface_uri) + if response['ret'] is False: + return response + current_hostinterface_config = response['data'] + payload = {} + for property in hostinterface_config.keys(): + value = hostinterface_config[property] + if property not in current_hostinterface_config: + return {'ret': False, 'msg': "Property %s in hostinterface_config is invalid" % property} + if isinstance(value, dict): + if isinstance(current_hostinterface_config[property], dict): + payload[property] = value + elif isinstance(current_hostinterface_config[property], list): + payload[property] = list() + payload[property].append(value) + else: + return {'ret': False, 'msg': "Value of property %s in hostinterface_config is invalid" % property} + else: + payload[property] = value + + need_change = False + for property in payload.keys(): + set_value = payload[property] + cur_value = current_hostinterface_config[property] + if not isinstance(set_value, dict) and not isinstance(set_value, list): + if set_value != cur_value: + need_change = True + if isinstance(set_value, dict): + for subprop in payload[property].keys(): + if subprop not in current_hostinterface_config[property]: + need_change = True + break + sub_set_value = payload[property][subprop] + sub_cur_value = current_hostinterface_config[property][subprop] + if sub_set_value != sub_cur_value: + need_change = True + if isinstance(set_value, list): + if len(set_value) != len(cur_value): + need_change = True + continue + for i in range(len(set_value)): + for subprop in payload[property][i].keys(): + if subprop not in current_hostinterface_config[property][i]: + need_change = True + break + sub_set_value = payload[property][i][subprop] + sub_cur_value = current_hostinterface_config[property][i][subprop] + if sub_set_value != sub_cur_value: + need_change = True + if not need_change: + return {'ret': True, 'changed': False, 'msg': "Host Interface already configured"} + + response = self.patch_request(self.root_uri + hostinterface_uri, payload) + if response['ret'] is False: + return response + return {'ret': True, 'changed': True, 'msg': "Modified Host Interface"} diff --git a/plugins/modules/remote_management/redfish/redfish_config.py b/plugins/modules/remote_management/redfish/redfish_config.py index ff4b15487e..b903ceed77 100644 --- a/plugins/modules/remote_management/redfish/redfish_config.py +++ b/plugins/modules/remote_management/redfish/redfish_config.py @@ -100,6 +100,18 @@ options: type: bool default: false version_added: 3.7.0 + hostinterface_config: + required: false + description: + - Setting dict of HostInterface on OOB controller. + type: dict + version_added: '4.1.0' + hostinterface_id: + required: false + description: + - Redfish HostInterface instance ID if multiple HostInterfaces are present. + type: str + version_added: '4.1.0' author: "Jose Delarosa (@jose-delarosa)" ''' @@ -201,6 +213,27 @@ EXAMPLES = ''' baseuri: "{{ baseuri }}" username: "{{ username }}" password: "{{ password }}" + + - name: Disable Host Interface + community.general.redfish_config: + category: Manager + command: SetHostInterface + hostinterface_config: + InterfaceEnabled: false + baseuri: "{{ baseuri }}" + username: "{{ username }}" + password: "{{ password }}" + + - name: Enable Host Interface for HostInterface resource ID '2' + community.general.redfish_config: + category: Manager + command: SetHostInterface + hostinterface_config: + InterfaceEnabled: true + hostinterface_id: "2" + baseuri: "{{ baseuri }}" + username: "{{ username }}" + password: "{{ password }}" ''' RETURN = ''' @@ -220,7 +253,7 @@ from ansible.module_utils.common.text.converters import to_native CATEGORY_COMMANDS_ALL = { "Systems": ["SetBiosDefaultSettings", "SetBiosAttributes", "SetBootOrder", "SetDefaultBootOrder"], - "Manager": ["SetNetworkProtocols", "SetManagerNic"] + "Manager": ["SetNetworkProtocols", "SetManagerNic", "SetHostInterface"] } @@ -248,6 +281,8 @@ def main(): default={} ), strip_etag_quotes=dict(type='bool', default=False), + hostinterface_config=dict(type='dict', default={}), + hostinterface_id=dict(), ), required_together=[ ('username', 'password'), @@ -288,6 +323,12 @@ def main(): # Etag options strip_etag_quotes = module.params['strip_etag_quotes'] + # HostInterface config options + hostinterface_config = module.params['hostinterface_config'] + + # HostInterface instance ID + hostinterface_id = module.params['hostinterface_id'] + # Build root URI root_uri = "https://" + module.params['baseuri'] rf_utils = RedfishUtils(creds, root_uri, timeout, module, @@ -331,6 +372,8 @@ def main(): result = rf_utils.set_network_protocols(module.params['network_protocols']) elif command == "SetManagerNic": result = rf_utils.set_manager_nic(nic_addr, nic_config) + elif command == "SetHostInterface": + result = rf_utils.set_hostinterface_attributes(hostinterface_config, hostinterface_id) # Return data back or fail with proper message if result['ret'] is True: