From 564f87c77506f9ef2897da05150f88a1d8875b56 Mon Sep 17 00:00:00 2001 From: "patchback[bot]" <45432694+patchback[bot]@users.noreply.github.com> Date: Sun, 16 Apr 2023 13:39:44 +0200 Subject: [PATCH] [PR #6115/f95b8ab9 backport][stable-6] Adding CheckiLORebootStatus functionality to ilo_redfish_command (#6339) Adding CheckiLORebootStatus functionality to ilo_redfish_command (#6115) * Adding CheckiLORebootStatus functionality to ilo_redfish_command * PR fix * Update plugins/modules/ilo_redfish_command.py Agreed Co-authored-by: Felix Fontein * sanity fix * Changed command to WaitforiLORebootCompletion * PR comment fix * Update plugins/modules/ilo_redfish_command.py Agreed Co-authored-by: Felix Fontein * Update plugins/modules/ilo_redfish_command.py Agreed Co-authored-by: Felix Fontein * Update plugins/modules/ilo_redfish_command.py Agreed Co-authored-by: Felix Fontein * Update plugins/modules/ilo_redfish_command.py Agreed Co-authored-by: Felix Fontein * Updating documentation based on PR comment * Adding tests and updating task name in module --------- Co-authored-by: Kushal Co-authored-by: Felix Fontein (cherry picked from commit f95b8ab9cd5a82c4548e32e34366ea57534d4eb6) Co-authored-by: TSKushal <44438079+TSKushal@users.noreply.github.com> --- .github/BOTMETA.yml | 2 +- plugins/module_utils/ilo_redfish_utils.py | 77 ++++++++ plugins/modules/ilo_redfish_command.py | 175 ++++++++++++++++++ .../targets/ilo_redfish_command/aliases | 5 + .../ilo_redfish_command/tasks/main.yml | 12 ++ 5 files changed, 270 insertions(+), 1 deletion(-) create mode 100644 plugins/modules/ilo_redfish_command.py create mode 100644 tests/integration/targets/ilo_redfish_command/aliases create mode 100644 tests/integration/targets/ilo_redfish_command/tasks/main.yml diff --git a/.github/BOTMETA.yml b/.github/BOTMETA.yml index 2e71a215c4..3a23f39bbd 100644 --- a/.github/BOTMETA.yml +++ b/.github/BOTMETA.yml @@ -589,7 +589,7 @@ files: ignore: jose-delarosa maintainers: $team_redfish $modules/ilo_: - ignore: jose-delarosa + ignore: jose-delarosa varini-hp maintainers: $team_redfish $modules/imc_rest.py: labels: cisco diff --git a/plugins/module_utils/ilo_redfish_utils.py b/plugins/module_utils/ilo_redfish_utils.py index a6ab42dba6..9cb6e527a3 100644 --- a/plugins/module_utils/ilo_redfish_utils.py +++ b/plugins/module_utils/ilo_redfish_utils.py @@ -8,6 +8,7 @@ from __future__ import absolute_import, division, print_function __metaclass__ = type from ansible_collections.community.general.plugins.module_utils.redfish_utils import RedfishUtils +import time class iLORedfishUtils(RedfishUtils): @@ -228,3 +229,79 @@ class iLORedfishUtils(RedfishUtils): if not response['ret']: return response return {'ret': True, 'changed': True, 'msg': "Modified %s" % mgrattr['mgr_attr_name']} + + def get_server_poststate(self): + # Get server details + response = self.get_request(self.root_uri + self.systems_uri) + if not response["ret"]: + return response + server_data = response["data"] + + if "Hpe" in server_data["Oem"]: + return { + "ret": True, + "server_poststate": server_data["Oem"]["Hpe"]["PostState"] + } + else: + return { + "ret": True, + "server_poststate": server_data["Oem"]["Hp"]["PostState"] + } + + def wait_for_ilo_reboot_completion(self, polling_interval=60, max_polling_time=1800): + # This method checks if OOB controller reboot is completed + time.sleep(10) + + # Check server poststate + state = self.get_server_poststate() + if not state["ret"]: + return state + + count = int(max_polling_time / polling_interval) + times = 0 + + # When server is powered OFF + pcount = 0 + while state["server_poststate"] in ["PowerOff", "Off"] and pcount < 5: + time.sleep(10) + state = self.get_server_poststate() + if not state["ret"]: + return state + + if state["server_poststate"] not in ["PowerOff", "Off"]: + break + pcount = pcount + 1 + if state["server_poststate"] in ["PowerOff", "Off"]: + return { + "ret": False, + "changed": False, + "msg": "Server is powered OFF" + } + + # When server is not rebooting + if state["server_poststate"] in ["InPostDiscoveryComplete", "FinishedPost"]: + return { + "ret": True, + "changed": False, + "msg": "Server is not rebooting" + } + + while state["server_poststate"] not in ["InPostDiscoveryComplete", "FinishedPost"] and count > times: + state = self.get_server_poststate() + if not state["ret"]: + return state + + if state["server_poststate"] in ["InPostDiscoveryComplete", "FinishedPost"]: + return { + "ret": True, + "changed": True, + "msg": "Server reboot is completed" + } + time.sleep(polling_interval) + times = times + 1 + + return { + "ret": False, + "changed": False, + "msg": "Server Reboot has failed, server state: {state} ".format(state=state) + } diff --git a/plugins/modules/ilo_redfish_command.py b/plugins/modules/ilo_redfish_command.py new file mode 100644 index 0000000000..0ec385e731 --- /dev/null +++ b/plugins/modules/ilo_redfish_command.py @@ -0,0 +1,175 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright (c) 2021-2022 Hewlett Packard Enterprise, Inc. All rights reserved. +# 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 + +DOCUMENTATION = ''' +--- +module: ilo_redfish_command +short_description: Manages Out-Of-Band controllers using Redfish APIs +version_added: 6.6.0 +description: + - Builds Redfish URIs locally and sends them to remote OOB controllers to + perform an action. +attributes: + check_mode: + support: none + diff_mode: + support: none +extends_documentation_fragment: + - community.general.attributes +options: + category: + required: true + description: + - Category to execute on OOB controller. + type: str + choices: ['Systems'] + command: + required: true + description: + - List of commands to execute on OOB controller. + type: list + elements: str + baseuri: + required: true + description: + - Base URI of OOB controller. + type: str + username: + required: false + description: + - Username for authenticating to iLO. + type: str + password: + required: false + description: + - Password for authenticating to iLO. + type: str + auth_token: + required: false + description: + - Security token for authenticating to iLO. + type: str + timeout: + required: false + description: + - Timeout in seconds for HTTP requests to iLO. + default: 60 + type: int +author: + - Varni H P (@varini-hp) +''' + +EXAMPLES = ''' + - name: Wait for iLO Reboot Completion + community.general.ilo_redfish_command: + category: Systems + command: WaitforiLORebootCompletion + baseuri: "{{ baseuri }}" + username: "{{ username }}" + password: "{{ password }}" +''' + +RETURN = ''' +ilo_redfish_command: + description: Returns the status of the operation performed on the iLO. + type: dict + contains: + WaitforiLORebootCompletion: + description: Returns the output msg and whether the function executed successfully. + type: dict + contains: + ret: + description: Return True/False based on whether the operation was performed succesfully. + type: bool + msg: + description: Status of the operation performed on the iLO. + type: str + returned: always +''' + +# More will be added as module features are expanded +CATEGORY_COMMANDS_ALL = { + "Systems": ["WaitforiLORebootCompletion"] +} + +from ansible_collections.community.general.plugins.module_utils.ilo_redfish_utils import iLORedfishUtils +from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.common.text.converters import to_native + + +def main(): + result = {} + 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) + ), + required_together=[ + ('username', 'password'), + ], + required_one_of=[ + ('username', 'auth_token'), + ], + mutually_exclusive=[ + ('username', 'auth_token'), + ], + supports_check_mode=False + ) + + category = module.params['category'] + command_list = module.params['command'] + + # admin credentials used for authentication + creds = {'user': module.params['username'], + 'pswd': module.params['password'], + 'token': module.params['auth_token']} + + timeout = module.params['timeout'] + + # Build root URI + root_uri = "https://" + module.params['baseuri'] + rf_utils = iLORedfishUtils(creds, root_uri, timeout, module) + + # Check that Category is valid + if category not in CATEGORY_COMMANDS_ALL: + module.fail_json(msg=to_native( + "Invalid Category '%s'. Valid Categories = %s" % (category, list(CATEGORY_COMMANDS_ALL.keys())))) + + # Check that all commands are valid + for cmd in command_list: + # Fail if even one command given is invalid + if cmd not in CATEGORY_COMMANDS_ALL[category]: + module.fail_json( + msg=to_native("Invalid Command '%s'. Valid Commands = %s" % (cmd, CATEGORY_COMMANDS_ALL[category]))) + + if category == "Systems": + # execute only if we find a System resource + + result = rf_utils._find_systems_resource() + if result['ret'] is False: + module.fail_json(msg=to_native(result['msg'])) + + for command in command_list: + if command == "WaitforiLORebootCompletion": + result[command] = rf_utils.wait_for_ilo_reboot_completion() + + # Return data back or fail with proper message + if not result[command]['ret']: + module.fail_json(msg=result) + + changed = result[command].get('changed', False) + module.exit_json(ilo_redfish_command=result, changed=changed) + + +if __name__ == '__main__': + main() diff --git a/tests/integration/targets/ilo_redfish_command/aliases b/tests/integration/targets/ilo_redfish_command/aliases new file mode 100644 index 0000000000..bd1f024441 --- /dev/null +++ b/tests/integration/targets/ilo_redfish_command/aliases @@ -0,0 +1,5 @@ +# Copyright (c) Ansible Project +# 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 + +unsupported diff --git a/tests/integration/targets/ilo_redfish_command/tasks/main.yml b/tests/integration/targets/ilo_redfish_command/tasks/main.yml new file mode 100644 index 0000000000..cc1fce748d --- /dev/null +++ b/tests/integration/targets/ilo_redfish_command/tasks/main.yml @@ -0,0 +1,12 @@ +--- +# Copyright (c) Ansible Project +# 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 + +- name: Wait for iLO Reboot Completion + community.general.ilo_redfish_command: + category: Systems + command: WaitforiLORebootCompletion + baseuri: "{{ baseuri }}" + username: "{{ username }}" + password: "{{ password }}"