From 89e90cbf91fd9d36db597392286101fea0a1241f Mon Sep 17 00:00:00 2001 From: munchtoast Date: Mon, 2 Jun 2025 16:35:27 -0400 Subject: [PATCH 1/8] feat(initial): Add pacemaker_stonith module and unit tests --- .github/BOTMETA.yml | 2 + plugins/modules/pacemaker_stonith.py | 218 ++++++++++++++++++ .../plugins/modules/test_pacemaker_stonith.py | 19 ++ .../modules/test_pacemaker_stonith.yaml | 206 +++++++++++++++++ 4 files changed, 445 insertions(+) create mode 100644 plugins/modules/pacemaker_stonith.py create mode 100644 tests/unit/plugins/modules/test_pacemaker_stonith.py create mode 100644 tests/unit/plugins/modules/test_pacemaker_stonith.yaml diff --git a/.github/BOTMETA.yml b/.github/BOTMETA.yml index fac3fae8f8..1817984697 100644 --- a/.github/BOTMETA.yml +++ b/.github/BOTMETA.yml @@ -1060,6 +1060,8 @@ files: maintainers: matbu munchtoast $modules/pacemaker_resource.py: maintainers: munchtoast + $modules/pacemaker_stonith.py: + maintainers: munchtoast $modules/packet_: maintainers: nurfet-becirevic t0mk $modules/packet_device.py: diff --git a/plugins/modules/pacemaker_stonith.py b/plugins/modules/pacemaker_stonith.py new file mode 100644 index 0000000000..71ed21e7c1 --- /dev/null +++ b/plugins/modules/pacemaker_stonith.py @@ -0,0 +1,218 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# Copyright (c) 2025, Dexter Le +# 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: pacemaker_stonith +short_description: Manage pacemaker stonith +author: + - Dexter Le (@munchtoast) +version_added: 10.6.0 +description: + - This module can manage stonith in a Pacemaker cluster using the pacemaker CLI. +extends_documentation_fragment: + - community.general.attributes +attributes: + check_mode: + support: full + diff_mode: + support: none +options: + state: + description: + - Indicate desired state for cluster stonith. + choices: [ present, absent, enabled, disabled ] + default: present + type: str + name: + description: + - Specify the stonith name to create. + required: true + type: str + stonith_type: + description: + - Specify the stonith device type + type: str + stonith_option: + description: + - Specify the stonith option to create. + type: list + elements: str + default: [] + stonith_operation: + description: + - List of operations to associate with stonith. + type: list + elements: dict + default: [] + suboptions: + operation_action: + description: + - Operation action to associate with stonith. + type: str + operation_option: + description: + - Operation option to associate with action. + type: list + elements: str + stonith_meta: + description: + - List of meta to associate with stonith. + type: list + elements: str + stonith_argument: + description: + - Action to associate with stonith. + type: dict + suboptions: + argument_action: + description: + - Action to apply to stonith. + type: str + choices: [ group, before, after ] + argument_option: + description: + - Options to associate with stonith action. + type: list + elements: str + agent_validation: + description: + - enabled agent validation for stonith creation. + type: bool + default: false + wait: + description: + - Timeout period for polling the stonith creation. + type: int + default: 300 +''' + +EXAMPLES = ''' +--- +- name: Create pacemaker stonith + hosts: localhost + gather_facts: false + tasks: + - name: Create virtual-ip stonith + community.general.pacemaker_stonith: + state: present + name: virtual-stonith + stonith_type: fence_virt + stonith_option: + - "pcmk_host_list=f1" + stonith_operation: + - operation_action: monitor + operation_option: + - "interval=30s" +''' + +RETURN = ''' +cluster_stonith: + description: The cluster stonith output message. + type: str + sample: "" + returned: always +''' + +from ansible_collections.community.general.plugins.module_utils.module_helper import StateModuleHelper +from ansible_collections.community.general.plugins.module_utils.pacemaker import pacemaker_runner + + +class PacemakerStonith(StateModuleHelper): + module = dict( + argument_spec=dict( + state=dict(type='str', default='present', choices=[ + 'present', 'absent', 'enabled', 'disabled']), + name=dict(type='str', required=True), + stonith_type=dict(type='str'), + stonith_option=dict(type='list', elements='str', default=list()), + stonith_operation=dict(type='list', elements='dict', default=list(), options=dict( + operation_action=dict(type='str'), + operation_option=dict(type='list', elements='str'), + )), + stonith_meta=dict(type='list', elements='str'), + stonith_argument=dict(type='dict', options=dict( + argument_action=dict(type='str', choices=['before', 'after', 'group']), + argument_option=dict(type='list', elements='str'), + )), + agent_validation=dict(type='bool', default=False), + wait=dict(type='int', default=300), + ), + required_if=[('state', 'present', ['stonith_type', 'stonith_option'])], + supports_check_mode=True + ) + + use_old_vardict = False + default_state = "present" + + def __init_module__(self): + self.runner = pacemaker_runner(self.module, cli_action='stonith') + self.vars.set('previous_value', self._get()) + self.vars.set('value', self.vars.previous_value, change=True, diff=True) + self.vars.set('resource_type', self.vars.stonith_type) + self.vars.set('resource_option', self.vars.stonith_option) + self.vars.set('resource_operation', self.vars.stonith_operation) + self.vars.set('resource_meta', self.vars.stonith_meta) + self.vars.set('resource_argument', self.vars.stonith_argument) + + def _process_command_output(self, fail_on_err, ignore_err_msg=""): + def process(rc, out, err): + if fail_on_err and rc != 0 and err and ignore_err_msg not in err: + self.do_raise('pcs failed with error (rc={0}): {1}'.format(rc, err)) + out = out.rstrip() + return None if out == "" else out + return process + + def _get(self): + with self.runner('state name', output_process=self._process_command_output(False)) as ctx: + return ctx.run(state='status') + + def state_absent(self): + with self.runner('state name', output_process=self._process_command_output(True, "does not exist"), check_mode_skip=True) as ctx: + ctx.run() + self.vars.set('value', self._get()) + self.vars.stdout = ctx.results_out + self.vars.stderr = ctx.results_err + self.vars.cmd = ctx.cmd + + def state_present(self): + with self.runner( + 'state name resource_type resource_option resource_operation resource_meta resource_argument wait', + output_process=self._process_command_output(True, "already exists"), + check_mode_skip=True) as ctx: + ctx.run() + self.vars.set('value', self._get()) + self.vars.stdout = ctx.results_out + self.vars.stderr = ctx.results_err + self.vars.cmd = ctx.cmd + + def state_enabled(self): + with self.runner('state name', output_process=self._process_command_output(True, "Starting"), check_mode_skip=True) as ctx: + ctx.run() + self.vars.set('value', self._get()) + self.vars.stdout = ctx.results_out + self.vars.stderr = ctx.results_err + self.vars.cmd = ctx.cmd + + def state_disabled(self): + with self.runner('state name', output_process=self._process_command_output(True, "Stopped"), check_mode_skip=True) as ctx: + ctx.run() + self.vars.set('value', self._get()) + self.vars.stdout = ctx.results_out + self.vars.stderr = ctx.results_err + self.vars.cmd = ctx.cmd + + +def main(): + PacemakerStonith.execute() + + +if __name__ == '__main__': + main() diff --git a/tests/unit/plugins/modules/test_pacemaker_stonith.py b/tests/unit/plugins/modules/test_pacemaker_stonith.py new file mode 100644 index 0000000000..c666918cf4 --- /dev/null +++ b/tests/unit/plugins/modules/test_pacemaker_stonith.py @@ -0,0 +1,19 @@ +# -*- coding: utf-8 -*- +# Author: Dexter Le (dextersydney2001@gmail.com) +# Largely adapted from test_redhat_subscription by +# Jiri Hnidek (jhnidek@redhat.com) +# +# Copyright (c) Dexter Le (dextersydney2001@gmail.com) +# Copyright (c) Jiri Hnidek (jhnidek@redhat.com) +# +# 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 + + +from ansible_collections.community.general.plugins.modules import pacemaker_stonith +from .uthelper import UTHelper, RunCommandMock + +UTHelper.from_module(pacemaker_stonith, __name__, mocks=[RunCommandMock]) diff --git a/tests/unit/plugins/modules/test_pacemaker_stonith.yaml b/tests/unit/plugins/modules/test_pacemaker_stonith.yaml new file mode 100644 index 0000000000..6c3a85f764 --- /dev/null +++ b/tests/unit/plugins/modules/test_pacemaker_stonith.yaml @@ -0,0 +1,206 @@ +# -*- coding: utf-8 -*- +# Copyright (c) Dexter Le (dextersydney2001@gmail.com) +# 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 + +--- +anchors: + environ: &env-def {environ_update: {LANGUAGE: C, LC_ALL: C}, check_rc: false} +test_cases: + - id: test_missing_input + input: {} + output: + failed: true + msg: "missing required arguments: name" + - id: test_present_minimal_input_stonith_not_exists + input: + state: present + name: virtual-stonith + stonith_type: fence_virt + stonith_option: + - "pcmk_host_list=f1" + stonith_operation: + - operation_action: monitor + operation_option: + - "interval=30s" + output: + changed: true + previous_value: null + value: " * virtual-stonith\t(stonith:fence_virt):\t Started" + mocks: + run_command: + - command: ["/testbin/pcs", stonith, status, virtual-stonith] + environ: *env-def + rc: 1 + out: "" + err: "" + - command: ["/testbin/pcs", stonith, create, virtual-stonith, fence_virt, "pcmk_host_list=f1", "op", "monitor", "interval=30s", "--wait=300"] + environ: *env-def + rc: 0 + out: "" + err: "" + - command: ["/testbin/pcs", stonith, status, virtual-stonith] + environ: *env-def + rc: 0 + out: " * virtual-stonith\t(stonith:fence_virt):\t Started" + err: "" + - id: test_present_minimal_input_stonith_exists + input: + state: present + name: virtual-stonith + stonith_type: fence_virt + stonith_option: + - "pcmk_host_list=f1" + stonith_operation: + - operation_action: monitor + operation_option: + - "interval=30s" + output: + changed: false + previous_value: " * virtual-stonith\t(stonith:fence_virt):\t Started" + value: " * virtual-stonith\t(stonith:fence_virt):\t Started" + mocks: + run_command: + - command: ["/testbin/pcs", stonith, status, virtual-stonith] + environ: *env-def + rc: 0 + out: " * virtual-stonith\t(stonith:fence_virt):\t Started" + err: "" + - command: ["/testbin/pcs", stonith, create, virtual-stonith, fence_virt, "pcmk_host_list=f1", "op", "monitor", "interval=30s", "--wait=300"] + environ: *env-def + rc: 0 + out: "" + err: "Error: 'virtual-stonith' already exists.\n" + - command: ["/testbin/pcs", stonith, status, virtual-stonith] + environ: *env-def + rc: 0 + out: " * virtual-stonith\t(stonith:fence_virt):\t Started" + err: "" + - id: test_absent_minimal_input_stonith_not_exists + input: + state: absent + name: virtual-stonith + output: + changed: false + previous_value: null + value: null + mocks: + run_command: + - command: ["/testbin/pcs", stonith, status, virtual-stonith] + environ: *env-def + rc: 1 + out: "" + err: "" + - command: ["/testbin/pcs", stonith, remove, virtual-stonith] + environ: *env-def + rc: 1 + out: "" + err: "Error: Resource 'virtual-stonith' does not exist.\n" + - id: test_absent_minimal_input_stonith_exists + input: + state: absent + name: virtual-stonith + output: + changed: true + previous_value: " * virtual-stonith\t(stonith:fence_virt):\t Started" + value: null + mocks: + run_command: + - command: ["/testbin/pcs", stonith, status, virtual-stonith] + environ: *env-def + rc: 0 + out: " * virtual-stonith\t(stonith:fence_virt):\t Started" + err: "" + - command: ["/testbin/pcs", stonith, remove, virtual-stonith] + environ: *env-def + rc: 0 + out: "" + err: "Attempting to stop: virtual-ip... Stopped\n" + - id: test_enabled_minimal_input_stonith_not_exists + input: + state: enabled + name: virtual-stonith + output: + failed: true + msg: "pcs failed with error (rc=1): Error: Resource 'virtual-stonith' does not exist." + mocks: + run_command: + - command: ["/testbin/pcs", stonith, status, virtual-stonith] + environ: *env-def + rc: 1 + out: "" + err: "" + - command: ["/testbin/pcs", stonith, enable, virtual-stonith] + environ: *env-def + rc: 1 + out: "" + err: "Error: Resource 'virtual-stonith' does not exist." + - id: test_enabled_minimal_input_stonith_exists + input: + state: enabled + name: virtual-stonith + output: + changed: true + previous_value: " * virtual-stonith\t(stonith:fence_virt):\t Stopped (disabled)" + value: " * virtual-stonith\t(stonith:fence_virt):\t Starting" + mocks: + run_command: + - command: ["/testbin/pcs", stonith, status, virtual-stonith] + environ: *env-def + rc: 0 + out: " * virtual-stonith\t(stonith:fence_virt):\t Stopped (disabled)" + err: "" + - command: ["/testbin/pcs", stonith, enable, virtual-stonith] + environ: *env-def + rc: 0 + out: "" + err: "" + - command: ["/testbin/pcs", stonith, status, virtual-stonith] + environ: *env-def + rc: 0 + out: " * virtual-stonith\t(stonith:fence_virt):\t Starting" + err: "" + - id: test_disable_minimal_input_stonith_not_exists + input: + state: disabled + name: virtual-stonith + output: + failed: true + msg: "pcs failed with error (rc=1): Error: Resource 'virtual-stonith' does not exist." + mocks: + run_command: + - command: ["/testbin/pcs", stonith, status, virtual-stonith] + environ: *env-def + rc: 1 + out: "" + err: "" + - command: ["/testbin/pcs", stonith, disable, virtual-stonith] + environ: *env-def + rc: 1 + out: "" + err: "Error: Resource 'virtual-stonith' does not exist." + - id: test_disable_minimal_input_stonith_exists + input: + state: disabled + name: virtual-stonith + output: + changed: true + previous_value: " * virtual-stonith\t(stonith:fence_virt):\t Started" + value: " * virtual-stonith\t(stonith:fence_virt):\t Stopped (disabled)" + mocks: + run_command: + - command: ["/testbin/pcs", stonith, status, virtual-stonith] + environ: *env-def + rc: 0 + out: " * virtual-stonith\t(stonith:fence_virt):\t Started" + err: "" + - command: ["/testbin/pcs", stonith, disable, virtual-stonith] + environ: *env-def + rc: 0 + out: "" + err: "" + - command: ["/testbin/pcs", stonith, status, virtual-stonith] + environ: *env-def + rc: 0 + out: " * virtual-stonith\t(stonith:fence_virt):\t Stopped (disabled)" + err: "" From 356c42ba3b1495767b75089865f87c9237b16e7f Mon Sep 17 00:00:00 2001 From: munchtoast Date: Wed, 4 Jun 2025 10:23:25 -0400 Subject: [PATCH 2/8] feat(initial): Add working changes to pacemaker_stonith --- plugins/modules/pacemaker_stonith.py | 12 ++++++------ .../unit/plugins/modules/test_pacemaker_stonith.yaml | 10 ++++++++++ 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/plugins/modules/pacemaker_stonith.py b/plugins/modules/pacemaker_stonith.py index 71ed21e7c1..000a62f22c 100644 --- a/plugins/modules/pacemaker_stonith.py +++ b/plugins/modules/pacemaker_stonith.py @@ -14,7 +14,7 @@ module: pacemaker_stonith short_description: Manage pacemaker stonith author: - Dexter Le (@munchtoast) -version_added: 10.6.0 +version_added: 10.8.0 description: - This module can manage stonith in a Pacemaker cluster using the pacemaker CLI. extends_documentation_fragment: @@ -156,11 +156,11 @@ class PacemakerStonith(StateModuleHelper): self.runner = pacemaker_runner(self.module, cli_action='stonith') self.vars.set('previous_value', self._get()) self.vars.set('value', self.vars.previous_value, change=True, diff=True) - self.vars.set('resource_type', self.vars.stonith_type) - self.vars.set('resource_option', self.vars.stonith_option) - self.vars.set('resource_operation', self.vars.stonith_operation) - self.vars.set('resource_meta', self.vars.stonith_meta) - self.vars.set('resource_argument', self.vars.stonith_argument) + self.module.params['resource_type'] = dict(resource_name=self.vars.stonith_type) + self.module.params['resource_option'] = self.vars.stonith_option + self.module.params['resource_operation'] = self.vars.stonith_operation + self.module.params['resource_meta'] = self.vars.stonith_meta + self.module.params['resource_argument'] = self.vars.stonith_argument def _process_command_output(self, fail_on_err, ignore_err_msg=""): def process(rc, out, err): diff --git a/tests/unit/plugins/modules/test_pacemaker_stonith.yaml b/tests/unit/plugins/modules/test_pacemaker_stonith.yaml index 6c3a85f764..8d938026ed 100644 --- a/tests/unit/plugins/modules/test_pacemaker_stonith.yaml +++ b/tests/unit/plugins/modules/test_pacemaker_stonith.yaml @@ -96,6 +96,11 @@ test_cases: rc: 1 out: "" err: "Error: Resource 'virtual-stonith' does not exist.\n" + - command: ["/testbin/pcs", stonith, status, virtual-stonith] + environ: *env-def + rc: 1 + out: "" + err: "" - id: test_absent_minimal_input_stonith_exists input: state: absent @@ -116,6 +121,11 @@ test_cases: rc: 0 out: "" err: "Attempting to stop: virtual-ip... Stopped\n" + - command: ["/testbin/pcs", stonith, status, virtual-stonith] + environ: *env-def + rc: 1 + out: "" + err: "" - id: test_enabled_minimal_input_stonith_not_exists input: state: enabled From 220bb72d6c6ee82a591b169b6b7ce13eadefb4df Mon Sep 17 00:00:00 2001 From: munchtoast Date: Wed, 18 Jun 2025 10:44:48 -0500 Subject: [PATCH 3/8] refactor(review): Apply code review suggestions --- plugins/module_utils/pacemaker.py | 1 + plugins/modules/pacemaker_stonith.py | 88 +++++++++++-------- .../modules/test_pacemaker_stonith.yaml | 12 +-- 3 files changed, 56 insertions(+), 45 deletions(-) diff --git a/plugins/module_utils/pacemaker.py b/plugins/module_utils/pacemaker.py index f0f54cce9d..443b120242 100644 --- a/plugins/module_utils/pacemaker.py +++ b/plugins/module_utils/pacemaker.py @@ -64,6 +64,7 @@ def pacemaker_runner(module, **kwargs): resource_meta=cmd_runner_fmt.stack(cmd_runner_fmt.as_opt_val)("meta"), resource_argument=cmd_runner_fmt.as_func(fmt_resource_argument), apply_all=cmd_runner_fmt.as_bool("--all"), + agent_validation=cmd_runner_fmt.as_bool("--agent-validation"), wait=cmd_runner_fmt.as_opt_eq_val("--wait"), config=cmd_runner_fmt.as_fixed("config"), force=cmd_runner_fmt.as_bool("--force"), diff --git a/plugins/modules/pacemaker_stonith.py b/plugins/modules/pacemaker_stonith.py index 000a62f22c..efeae61288 100644 --- a/plugins/modules/pacemaker_stonith.py +++ b/plugins/modules/pacemaker_stonith.py @@ -11,12 +11,12 @@ __metaclass__ = type DOCUMENTATION = ''' --- module: pacemaker_stonith -short_description: Manage pacemaker stonith +short_description: Manage pacemaker STONITH author: - Dexter Le (@munchtoast) -version_added: 10.8.0 +version_added: 11.1.0 description: - - This module can manage stonith in a Pacemaker cluster using the pacemaker CLI. + - This module can manage STONITH in a Pacemaker cluster using the pacemaker CLI. extends_documentation_fragment: - community.general.attributes attributes: @@ -27,95 +27,95 @@ attributes: options: state: description: - - Indicate desired state for cluster stonith. + - Indicate desired state for cluster STONITH. choices: [ present, absent, enabled, disabled ] default: present type: str name: description: - - Specify the stonith name to create. + - Specify the STONITH name to create. required: true type: str stonith_type: description: - - Specify the stonith device type + - Specify the STONITH device type type: str - stonith_option: + stonith_options: description: - - Specify the stonith option to create. + - Specify the STONITH option to create. type: list elements: str default: [] - stonith_operation: + stonith_operations: description: - - List of operations to associate with stonith. + - List of operations to associate with STONITH. type: list elements: dict default: [] suboptions: operation_action: description: - - Operation action to associate with stonith. + - Operation action to associate with STONITH. type: str - operation_option: + operation_options: description: - Operation option to associate with action. type: list elements: str - stonith_meta: + stonith_metas: description: - - List of meta to associate with stonith. + - List of meta to associate with STONITH. type: list elements: str stonith_argument: description: - - Action to associate with stonith. + - Action to associate with STONITH. type: dict suboptions: argument_action: description: - - Action to apply to stonith. + - Action to apply to STONITH. type: str choices: [ group, before, after ] - argument_option: + argument_options: description: - - Options to associate with stonith action. + - Options to associate with STONITH action. type: list elements: str agent_validation: description: - - enabled agent validation for stonith creation. + - enabled agent validation for STONITH creation. type: bool default: false wait: description: - - Timeout period for polling the stonith creation. + - Timeout period for polling the STONITH creation. type: int default: 300 ''' EXAMPLES = ''' --- -- name: Create pacemaker stonith +- name: Create pacemaker STONITH hosts: localhost gather_facts: false tasks: - - name: Create virtual-ip stonith + - name: Create virtual-ip STONITH community.general.pacemaker_stonith: state: present name: virtual-stonith stonith_type: fence_virt - stonith_option: + stonith_options: - "pcmk_host_list=f1" - stonith_operation: + stonith_operations: - operation_action: monitor - operation_option: + operation_options: - "interval=30s" ''' RETURN = ''' cluster_stonith: - description: The cluster stonith output message. + description: The cluster STONITH output message. type: str sample: "" returned: always @@ -132,20 +132,20 @@ class PacemakerStonith(StateModuleHelper): 'present', 'absent', 'enabled', 'disabled']), name=dict(type='str', required=True), stonith_type=dict(type='str'), - stonith_option=dict(type='list', elements='str', default=list()), - stonith_operation=dict(type='list', elements='dict', default=list(), options=dict( + stonith_options=dict(type='list', elements='str', default=list()), + stonith_operations=dict(type='list', elements='dict', default=list(), options=dict( operation_action=dict(type='str'), - operation_option=dict(type='list', elements='str'), + operation_options=dict(type='list', elements='str'), )), - stonith_meta=dict(type='list', elements='str'), + stonith_metas=dict(type='list', elements='str'), stonith_argument=dict(type='dict', options=dict( argument_action=dict(type='str', choices=['before', 'after', 'group']), - argument_option=dict(type='list', elements='str'), + argument_options=dict(type='list', elements='str'), )), agent_validation=dict(type='bool', default=False), wait=dict(type='int', default=300), ), - required_if=[('state', 'present', ['stonith_type', 'stonith_option'])], + required_if=[('state', 'present', ['stonith_type', 'stonith_options'])], supports_check_mode=True ) @@ -156,11 +156,6 @@ class PacemakerStonith(StateModuleHelper): self.runner = pacemaker_runner(self.module, cli_action='stonith') self.vars.set('previous_value', self._get()) self.vars.set('value', self.vars.previous_value, change=True, diff=True) - self.module.params['resource_type'] = dict(resource_name=self.vars.stonith_type) - self.module.params['resource_option'] = self.vars.stonith_option - self.module.params['resource_operation'] = self.vars.stonith_operation - self.module.params['resource_meta'] = self.vars.stonith_meta - self.module.params['resource_argument'] = self.vars.stonith_argument def _process_command_output(self, fail_on_err, ignore_err_msg=""): def process(rc, out, err): @@ -174,6 +169,17 @@ class PacemakerStonith(StateModuleHelper): with self.runner('state name', output_process=self._process_command_output(False)) as ctx: return ctx.run(state='status') + def _fmt_stonith_resource(self): + return dict([("resource_name", self.vars.stonith_type)]) + + # TODO: Pluralize operation_options in separate PR and remove this helper fmt function + def _fmt_stonith_operations(self): + modified_stonith_operations = [] + for stonith_operation in self.vars.stonith_operations: + modified_stonith_operations.append(dict([("operation_action", stonith_operation.get('operation_action')), + ("operation_option", stonith_operation.get('operation_options'))])) + return modified_stonith_operations + def state_absent(self): with self.runner('state name', output_process=self._process_command_output(True, "does not exist"), check_mode_skip=True) as ctx: ctx.run() @@ -184,10 +190,14 @@ class PacemakerStonith(StateModuleHelper): def state_present(self): with self.runner( - 'state name resource_type resource_option resource_operation resource_meta resource_argument wait', + 'state name resource_type resource_option resource_operation resource_meta resource_argument agent_validation wait', output_process=self._process_command_output(True, "already exists"), check_mode_skip=True) as ctx: - ctx.run() + ctx.run(resource_type=self._fmt_stonith_resource(), + resource_option=self.vars.stonith_options, + resource_operation=self._fmt_stonith_operations(), + resource_meta=self.vars.stonith_metas, + resource_argument=self.vars.stonith_argument) self.vars.set('value', self._get()) self.vars.stdout = ctx.results_out self.vars.stderr = ctx.results_err diff --git a/tests/unit/plugins/modules/test_pacemaker_stonith.yaml b/tests/unit/plugins/modules/test_pacemaker_stonith.yaml index 8d938026ed..321d3a0b1a 100644 --- a/tests/unit/plugins/modules/test_pacemaker_stonith.yaml +++ b/tests/unit/plugins/modules/test_pacemaker_stonith.yaml @@ -17,11 +17,11 @@ test_cases: state: present name: virtual-stonith stonith_type: fence_virt - stonith_option: + stonith_options: - "pcmk_host_list=f1" - stonith_operation: + stonith_operations: - operation_action: monitor - operation_option: + operation_options: - "interval=30s" output: changed: true @@ -49,11 +49,11 @@ test_cases: state: present name: virtual-stonith stonith_type: fence_virt - stonith_option: + stonith_options: - "pcmk_host_list=f1" - stonith_operation: + stonith_operations: - operation_action: monitor - operation_option: + operation_options: - "interval=30s" output: changed: false From cfd1167ee8108d67fae7af9a5b685b687822d7a4 Mon Sep 17 00:00:00 2001 From: Dexter <45038532+munchtoast@users.noreply.github.com> Date: Wed, 2 Jul 2025 14:51:20 -0400 Subject: [PATCH 4/8] Apply suggestions from code review Co-authored-by: Felix Fontein Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com> --- plugins/modules/pacemaker_stonith.py | 45 ++++++++++++---------------- 1 file changed, 19 insertions(+), 26 deletions(-) diff --git a/plugins/modules/pacemaker_stonith.py b/plugins/modules/pacemaker_stonith.py index efeae61288..aefe6bdc47 100644 --- a/plugins/modules/pacemaker_stonith.py +++ b/plugins/modules/pacemaker_stonith.py @@ -9,14 +9,13 @@ from __future__ import absolute_import, division, print_function __metaclass__ = type DOCUMENTATION = ''' ---- module: pacemaker_stonith short_description: Manage pacemaker STONITH author: - Dexter Le (@munchtoast) version_added: 11.1.0 description: - - This module can manage STONITH in a Pacemaker cluster using the pacemaker CLI. + - This module manages STONITH in a Pacemaker cluster using the pacemaker CLI. extends_documentation_fragment: - community.general.attributes attributes: @@ -38,7 +37,7 @@ options: type: str stonith_type: description: - - Specify the STONITH device type + - Specify the STONITH device type. type: str stonith_options: description: @@ -59,12 +58,12 @@ options: type: str operation_options: description: - - Operation option to associate with action. + - Operation options to associate with action. type: list elements: str stonith_metas: description: - - List of meta to associate with STONITH. + - List of metadata to associate with STONITH. type: list elements: str stonith_argument: @@ -84,7 +83,7 @@ options: elements: str agent_validation: description: - - enabled agent validation for STONITH creation. + - Enabled agent validation for STONITH creation. type: bool default: false wait: @@ -95,22 +94,17 @@ options: ''' EXAMPLES = ''' ---- -- name: Create pacemaker STONITH - hosts: localhost - gather_facts: false - tasks: - - name: Create virtual-ip STONITH - community.general.pacemaker_stonith: - state: present - name: virtual-stonith - stonith_type: fence_virt - stonith_options: - - "pcmk_host_list=f1" - stonith_operations: - - operation_action: monitor - operation_options: - - "interval=30s" +- name: Create virtual-ip STONITH + community.general.pacemaker_stonith: + state: present + name: virtual-stonith + stonith_type: fence_virt + stonith_options: + - "pcmk_host_list=f1" + stonith_operations: + - operation_action: monitor + operation_options: + - "interval=30s" ''' RETURN = ''' @@ -132,8 +126,8 @@ class PacemakerStonith(StateModuleHelper): 'present', 'absent', 'enabled', 'disabled']), name=dict(type='str', required=True), stonith_type=dict(type='str'), - stonith_options=dict(type='list', elements='str', default=list()), - stonith_operations=dict(type='list', elements='dict', default=list(), options=dict( + stonith_options=dict(type='list', elements='str', default=[]), + stonith_operations=dict(type='list', elements='dict', default=[], options=dict( operation_action=dict(type='str'), operation_options=dict(type='list', elements='str'), )), @@ -149,7 +143,6 @@ class PacemakerStonith(StateModuleHelper): supports_check_mode=True ) - use_old_vardict = False default_state = "present" def __init_module__(self): @@ -177,7 +170,7 @@ class PacemakerStonith(StateModuleHelper): modified_stonith_operations = [] for stonith_operation in self.vars.stonith_operations: modified_stonith_operations.append(dict([("operation_action", stonith_operation.get('operation_action')), - ("operation_option", stonith_operation.get('operation_options'))])) + ("operation_option", stonith_operation.get('operation_options'))])) return modified_stonith_operations def state_absent(self): From 00b87134f8b5819b102b8b37e4d6e20b1a492343 Mon Sep 17 00:00:00 2001 From: munchtoast Date: Wed, 2 Jul 2025 16:25:09 -0400 Subject: [PATCH 5/8] refactor(review): Additional code review items --- plugins/modules/pacemaker_stonith.py | 50 ++-- .../modules/test_pacemaker_stonith.yaml | 220 +++++++++--------- 2 files changed, 129 insertions(+), 141 deletions(-) diff --git a/plugins/modules/pacemaker_stonith.py b/plugins/modules/pacemaker_stonith.py index aefe6bdc47..c72a6902b7 100644 --- a/plugins/modules/pacemaker_stonith.py +++ b/plugins/modules/pacemaker_stonith.py @@ -27,7 +27,7 @@ options: state: description: - Indicate desired state for cluster STONITH. - choices: [ present, absent, enabled, disabled ] + choices: [present, absent, enabled, disabled] default: present type: str name: @@ -75,7 +75,7 @@ options: description: - Action to apply to STONITH. type: str - choices: [ group, before, after ] + choices: [group, before, after] argument_options: description: - Options to associate with STONITH action. @@ -109,10 +109,10 @@ EXAMPLES = ''' RETURN = ''' cluster_stonith: - description: The cluster STONITH output message. - type: str - sample: "" - returned: always + description: The cluster STONITH output message. + type: str + sample: "" + returned: always ''' from ansible_collections.community.general.plugins.module_utils.module_helper import StateModuleHelper @@ -143,13 +143,14 @@ class PacemakerStonith(StateModuleHelper): supports_check_mode=True ) - default_state = "present" - def __init_module__(self): self.runner = pacemaker_runner(self.module, cli_action='stonith') - self.vars.set('previous_value', self._get()) + self.vars.set('previous_value', self._get()['out']) self.vars.set('value', self.vars.previous_value, change=True, diff=True) + def __quit_module__(self): + self.vars.set('value', self._get()['out']) + def _process_command_output(self, fail_on_err, ignore_err_msg=""): def process(rc, out, err): if fail_on_err and rc != 0 and err and ignore_err_msg not in err: @@ -159,14 +160,17 @@ class PacemakerStonith(StateModuleHelper): return process def _get(self): - with self.runner('state name', output_process=self._process_command_output(False)) as ctx: - return ctx.run(state='status') + with self.runner('state name') as ctx: + result = ctx.run(state='status') + return dict([('rc', result[0]), + ('out', result[1] if result[1] != "" else None), + ('err', result[2])]) - def _fmt_stonith_resource(self): + def fmt_stonith_resource(self): return dict([("resource_name", self.vars.stonith_type)]) # TODO: Pluralize operation_options in separate PR and remove this helper fmt function - def _fmt_stonith_operations(self): + def fmt_stonith_operations(self): modified_stonith_operations = [] for stonith_operation in self.vars.stonith_operations: modified_stonith_operations.append(dict([("operation_action", stonith_operation.get('operation_action')), @@ -176,41 +180,25 @@ class PacemakerStonith(StateModuleHelper): def state_absent(self): with self.runner('state name', output_process=self._process_command_output(True, "does not exist"), check_mode_skip=True) as ctx: ctx.run() - self.vars.set('value', self._get()) - self.vars.stdout = ctx.results_out - self.vars.stderr = ctx.results_err - self.vars.cmd = ctx.cmd def state_present(self): with self.runner( 'state name resource_type resource_option resource_operation resource_meta resource_argument agent_validation wait', output_process=self._process_command_output(True, "already exists"), check_mode_skip=True) as ctx: - ctx.run(resource_type=self._fmt_stonith_resource(), + ctx.run(resource_type=self.fmt_stonith_resource(), resource_option=self.vars.stonith_options, - resource_operation=self._fmt_stonith_operations(), + resource_operation=self.fmt_stonith_operations(), resource_meta=self.vars.stonith_metas, resource_argument=self.vars.stonith_argument) - self.vars.set('value', self._get()) - self.vars.stdout = ctx.results_out - self.vars.stderr = ctx.results_err - self.vars.cmd = ctx.cmd def state_enabled(self): with self.runner('state name', output_process=self._process_command_output(True, "Starting"), check_mode_skip=True) as ctx: ctx.run() - self.vars.set('value', self._get()) - self.vars.stdout = ctx.results_out - self.vars.stderr = ctx.results_err - self.vars.cmd = ctx.cmd def state_disabled(self): with self.runner('state name', output_process=self._process_command_output(True, "Stopped"), check_mode_skip=True) as ctx: ctx.run() - self.vars.set('value', self._get()) - self.vars.stdout = ctx.results_out - self.vars.stderr = ctx.results_err - self.vars.cmd = ctx.cmd def main(): diff --git a/tests/unit/plugins/modules/test_pacemaker_stonith.yaml b/tests/unit/plugins/modules/test_pacemaker_stonith.yaml index 321d3a0b1a..5e1b03f85e 100644 --- a/tests/unit/plugins/modules/test_pacemaker_stonith.yaml +++ b/tests/unit/plugins/modules/test_pacemaker_stonith.yaml @@ -29,21 +29,21 @@ test_cases: value: " * virtual-stonith\t(stonith:fence_virt):\t Started" mocks: run_command: - - command: ["/testbin/pcs", stonith, status, virtual-stonith] - environ: *env-def - rc: 1 - out: "" - err: "" - - command: ["/testbin/pcs", stonith, create, virtual-stonith, fence_virt, "pcmk_host_list=f1", "op", "monitor", "interval=30s", "--wait=300"] - environ: *env-def - rc: 0 - out: "" - err: "" - - command: ["/testbin/pcs", stonith, status, virtual-stonith] - environ: *env-def - rc: 0 - out: " * virtual-stonith\t(stonith:fence_virt):\t Started" - err: "" + - command: ["/testbin/pcs", stonith, status, virtual-stonith] + environ: *env-def + rc: 1 + out: "" + err: "" + - command: ["/testbin/pcs", stonith, create, virtual-stonith, fence_virt, "pcmk_host_list=f1", "op", "monitor", "interval=30s", "--wait=300"] + environ: *env-def + rc: 0 + out: "" + err: "" + - command: ["/testbin/pcs", stonith, status, virtual-stonith] + environ: *env-def + rc: 0 + out: " * virtual-stonith\t(stonith:fence_virt):\t Started" + err: "" - id: test_present_minimal_input_stonith_exists input: state: present @@ -61,21 +61,21 @@ test_cases: value: " * virtual-stonith\t(stonith:fence_virt):\t Started" mocks: run_command: - - command: ["/testbin/pcs", stonith, status, virtual-stonith] - environ: *env-def - rc: 0 - out: " * virtual-stonith\t(stonith:fence_virt):\t Started" - err: "" - - command: ["/testbin/pcs", stonith, create, virtual-stonith, fence_virt, "pcmk_host_list=f1", "op", "monitor", "interval=30s", "--wait=300"] - environ: *env-def - rc: 0 - out: "" - err: "Error: 'virtual-stonith' already exists.\n" - - command: ["/testbin/pcs", stonith, status, virtual-stonith] - environ: *env-def - rc: 0 - out: " * virtual-stonith\t(stonith:fence_virt):\t Started" - err: "" + - command: ["/testbin/pcs", stonith, status, virtual-stonith] + environ: *env-def + rc: 0 + out: " * virtual-stonith\t(stonith:fence_virt):\t Started" + err: "" + - command: ["/testbin/pcs", stonith, create, virtual-stonith, fence_virt, "pcmk_host_list=f1", "op", "monitor", "interval=30s", "--wait=300"] + environ: *env-def + rc: 0 + out: "" + err: "Error: 'virtual-stonith' already exists.\n" + - command: ["/testbin/pcs", stonith, status, virtual-stonith] + environ: *env-def + rc: 0 + out: " * virtual-stonith\t(stonith:fence_virt):\t Started" + err: "" - id: test_absent_minimal_input_stonith_not_exists input: state: absent @@ -86,21 +86,21 @@ test_cases: value: null mocks: run_command: - - command: ["/testbin/pcs", stonith, status, virtual-stonith] - environ: *env-def - rc: 1 - out: "" - err: "" - - command: ["/testbin/pcs", stonith, remove, virtual-stonith] - environ: *env-def - rc: 1 - out: "" - err: "Error: Resource 'virtual-stonith' does not exist.\n" - - command: ["/testbin/pcs", stonith, status, virtual-stonith] - environ: *env-def - rc: 1 - out: "" - err: "" + - command: ["/testbin/pcs", stonith, status, virtual-stonith] + environ: *env-def + rc: 1 + out: "" + err: "" + - command: ["/testbin/pcs", stonith, remove, virtual-stonith] + environ: *env-def + rc: 1 + out: "" + err: "Error: Resource 'virtual-stonith' does not exist.\n" + - command: ["/testbin/pcs", stonith, status, virtual-stonith] + environ: *env-def + rc: 1 + out: "" + err: "" - id: test_absent_minimal_input_stonith_exists input: state: absent @@ -111,21 +111,21 @@ test_cases: value: null mocks: run_command: - - command: ["/testbin/pcs", stonith, status, virtual-stonith] - environ: *env-def - rc: 0 - out: " * virtual-stonith\t(stonith:fence_virt):\t Started" - err: "" - - command: ["/testbin/pcs", stonith, remove, virtual-stonith] - environ: *env-def - rc: 0 - out: "" - err: "Attempting to stop: virtual-ip... Stopped\n" - - command: ["/testbin/pcs", stonith, status, virtual-stonith] - environ: *env-def - rc: 1 - out: "" - err: "" + - command: ["/testbin/pcs", stonith, status, virtual-stonith] + environ: *env-def + rc: 0 + out: " * virtual-stonith\t(stonith:fence_virt):\t Started" + err: "" + - command: ["/testbin/pcs", stonith, remove, virtual-stonith] + environ: *env-def + rc: 0 + out: "" + err: "Attempting to stop: virtual-ip... Stopped\n" + - command: ["/testbin/pcs", stonith, status, virtual-stonith] + environ: *env-def + rc: 1 + out: "" + err: "" - id: test_enabled_minimal_input_stonith_not_exists input: state: enabled @@ -135,16 +135,16 @@ test_cases: msg: "pcs failed with error (rc=1): Error: Resource 'virtual-stonith' does not exist." mocks: run_command: - - command: ["/testbin/pcs", stonith, status, virtual-stonith] - environ: *env-def - rc: 1 - out: "" - err: "" - - command: ["/testbin/pcs", stonith, enable, virtual-stonith] - environ: *env-def - rc: 1 - out: "" - err: "Error: Resource 'virtual-stonith' does not exist." + - command: ["/testbin/pcs", stonith, status, virtual-stonith] + environ: *env-def + rc: 1 + out: "" + err: "" + - command: ["/testbin/pcs", stonith, enable, virtual-stonith] + environ: *env-def + rc: 1 + out: "" + err: "Error: Resource 'virtual-stonith' does not exist." - id: test_enabled_minimal_input_stonith_exists input: state: enabled @@ -155,21 +155,21 @@ test_cases: value: " * virtual-stonith\t(stonith:fence_virt):\t Starting" mocks: run_command: - - command: ["/testbin/pcs", stonith, status, virtual-stonith] - environ: *env-def - rc: 0 - out: " * virtual-stonith\t(stonith:fence_virt):\t Stopped (disabled)" - err: "" - - command: ["/testbin/pcs", stonith, enable, virtual-stonith] - environ: *env-def - rc: 0 - out: "" - err: "" - - command: ["/testbin/pcs", stonith, status, virtual-stonith] - environ: *env-def - rc: 0 - out: " * virtual-stonith\t(stonith:fence_virt):\t Starting" - err: "" + - command: ["/testbin/pcs", stonith, status, virtual-stonith] + environ: *env-def + rc: 0 + out: " * virtual-stonith\t(stonith:fence_virt):\t Stopped (disabled)" + err: "" + - command: ["/testbin/pcs", stonith, enable, virtual-stonith] + environ: *env-def + rc: 0 + out: "" + err: "" + - command: ["/testbin/pcs", stonith, status, virtual-stonith] + environ: *env-def + rc: 0 + out: " * virtual-stonith\t(stonith:fence_virt):\t Starting" + err: "" - id: test_disable_minimal_input_stonith_not_exists input: state: disabled @@ -179,16 +179,16 @@ test_cases: msg: "pcs failed with error (rc=1): Error: Resource 'virtual-stonith' does not exist." mocks: run_command: - - command: ["/testbin/pcs", stonith, status, virtual-stonith] - environ: *env-def - rc: 1 - out: "" - err: "" - - command: ["/testbin/pcs", stonith, disable, virtual-stonith] - environ: *env-def - rc: 1 - out: "" - err: "Error: Resource 'virtual-stonith' does not exist." + - command: ["/testbin/pcs", stonith, status, virtual-stonith] + environ: *env-def + rc: 1 + out: "" + err: "" + - command: ["/testbin/pcs", stonith, disable, virtual-stonith] + environ: *env-def + rc: 1 + out: "" + err: "Error: Resource 'virtual-stonith' does not exist." - id: test_disable_minimal_input_stonith_exists input: state: disabled @@ -199,18 +199,18 @@ test_cases: value: " * virtual-stonith\t(stonith:fence_virt):\t Stopped (disabled)" mocks: run_command: - - command: ["/testbin/pcs", stonith, status, virtual-stonith] - environ: *env-def - rc: 0 - out: " * virtual-stonith\t(stonith:fence_virt):\t Started" - err: "" - - command: ["/testbin/pcs", stonith, disable, virtual-stonith] - environ: *env-def - rc: 0 - out: "" - err: "" - - command: ["/testbin/pcs", stonith, status, virtual-stonith] - environ: *env-def - rc: 0 - out: " * virtual-stonith\t(stonith:fence_virt):\t Stopped (disabled)" - err: "" + - command: ["/testbin/pcs", stonith, status, virtual-stonith] + environ: *env-def + rc: 0 + out: " * virtual-stonith\t(stonith:fence_virt):\t Started" + err: "" + - command: ["/testbin/pcs", stonith, disable, virtual-stonith] + environ: *env-def + rc: 0 + out: "" + err: "" + - command: ["/testbin/pcs", stonith, status, virtual-stonith] + environ: *env-def + rc: 0 + out: " * virtual-stonith\t(stonith:fence_virt):\t Stopped (disabled)" + err: "" From 9db3f09be7ff4f40da82fed6db080456b6ce6ea8 Mon Sep 17 00:00:00 2001 From: munchtoast Date: Mon, 14 Jul 2025 12:13:55 -0400 Subject: [PATCH 6/8] bug(cli_action): Add missing runner arguments --- plugins/modules/pacemaker_stonith.py | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/plugins/modules/pacemaker_stonith.py b/plugins/modules/pacemaker_stonith.py index c72a6902b7..3d5f3e0985 100644 --- a/plugins/modules/pacemaker_stonith.py +++ b/plugins/modules/pacemaker_stonith.py @@ -144,7 +144,7 @@ class PacemakerStonith(StateModuleHelper): ) def __init_module__(self): - self.runner = pacemaker_runner(self.module, cli_action='stonith') + self.runner = pacemaker_runner(self.module) self.vars.set('previous_value', self._get()['out']) self.vars.set('value', self.vars.previous_value, change=True, diff=True) @@ -160,8 +160,8 @@ class PacemakerStonith(StateModuleHelper): return process def _get(self): - with self.runner('state name') as ctx: - result = ctx.run(state='status') + with self.runner('cli_action state name') as ctx: + result = ctx.run(cli_action='stonith', state='status') return dict([('rc', result[0]), ('out', result[1] if result[1] != "" else None), ('err', result[2])]) @@ -178,27 +178,28 @@ class PacemakerStonith(StateModuleHelper): return modified_stonith_operations def state_absent(self): - with self.runner('state name', output_process=self._process_command_output(True, "does not exist"), check_mode_skip=True) as ctx: - ctx.run() + with self.runner('cli_action state name', output_process=self._process_command_output(True, "does not exist"), check_mode_skip=True) as ctx: + ctx.run(cli_action='stonith') def state_present(self): with self.runner( - 'state name resource_type resource_option resource_operation resource_meta resource_argument agent_validation wait', + 'cli_action state name resource_type resource_option resource_operation resource_meta resource_argument agent_validation wait', output_process=self._process_command_output(True, "already exists"), check_mode_skip=True) as ctx: - ctx.run(resource_type=self.fmt_stonith_resource(), + ctx.run(cli_action='stonith', + resource_type=self.fmt_stonith_resource(), resource_option=self.vars.stonith_options, resource_operation=self.fmt_stonith_operations(), resource_meta=self.vars.stonith_metas, resource_argument=self.vars.stonith_argument) def state_enabled(self): - with self.runner('state name', output_process=self._process_command_output(True, "Starting"), check_mode_skip=True) as ctx: - ctx.run() + with self.runner('cli_action state name', output_process=self._process_command_output(True, "Starting"), check_mode_skip=True) as ctx: + ctx.run(cli_action='stonith') def state_disabled(self): - with self.runner('state name', output_process=self._process_command_output(True, "Stopped"), check_mode_skip=True) as ctx: - ctx.run() + with self.runner('cli_action state name', output_process=self._process_command_output(True, "Stopped"), check_mode_skip=True) as ctx: + ctx.run(cli_action='stonith') def main(): From 6f2a8553ee3f7af1a6a5543567439799f3fc92d3 Mon Sep 17 00:00:00 2001 From: munchtoast Date: Wed, 16 Jul 2025 14:58:24 -0400 Subject: [PATCH 7/8] Apply code review suggestions --- plugins/modules/pacemaker_stonith.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/plugins/modules/pacemaker_stonith.py b/plugins/modules/pacemaker_stonith.py index 3d5f3e0985..d6982f5cad 100644 --- a/plugins/modules/pacemaker_stonith.py +++ b/plugins/modules/pacemaker_stonith.py @@ -13,9 +13,13 @@ module: pacemaker_stonith short_description: Manage pacemaker STONITH author: - Dexter Le (@munchtoast) -version_added: 11.1.0 +version_added: 11.2.0 description: - This module manages STONITH in a Pacemaker cluster using the pacemaker CLI. +seealso: + - name: Pacemaker STONITH documentation + description: Complete documentation for Pacemaker STONITH. + link: https://clusterlabs.org/projects/pacemaker/doc/3.0/Pacemaker_Explained/html/resources.html#stonith extends_documentation_fragment: - community.general.attributes attributes: @@ -122,8 +126,7 @@ from ansible_collections.community.general.plugins.module_utils.pacemaker import class PacemakerStonith(StateModuleHelper): module = dict( argument_spec=dict( - state=dict(type='str', default='present', choices=[ - 'present', 'absent', 'enabled', 'disabled']), + state=dict(type='str', default='present', choices=['present', 'absent', 'enabled', 'disabled']), name=dict(type='str', required=True), stonith_type=dict(type='str'), stonith_options=dict(type='list', elements='str', default=[]), From 8ab06cba80bfa4b71d2e9fe7f6af956f661e7af1 Mon Sep 17 00:00:00 2001 From: Dexter <45038532+munchtoast@users.noreply.github.com> Date: Mon, 28 Jul 2025 09:17:50 -0400 Subject: [PATCH 8/8] Apply suggestions from code review Co-authored-by: Felix Fontein --- plugins/modules/pacemaker_stonith.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/modules/pacemaker_stonith.py b/plugins/modules/pacemaker_stonith.py index d6982f5cad..bc1bbb8fc4 100644 --- a/plugins/modules/pacemaker_stonith.py +++ b/plugins/modules/pacemaker_stonith.py @@ -10,12 +10,12 @@ __metaclass__ = type DOCUMENTATION = ''' module: pacemaker_stonith -short_description: Manage pacemaker STONITH +short_description: Manage Pacemaker STONITH author: - Dexter Le (@munchtoast) version_added: 11.2.0 description: - - This module manages STONITH in a Pacemaker cluster using the pacemaker CLI. + - This module manages STONITH in a Pacemaker cluster using the Pacemaker CLI. seealso: - name: Pacemaker STONITH documentation description: Complete documentation for Pacemaker STONITH.