mirror of
https://github.com/ansible-collections/community.general.git
synced 2025-08-03 20:54:24 -07:00
Merge 8ab06cba80
into 84b5d38c51
This commit is contained in:
commit
b224dafbb7
5 changed files with 451 additions and 0 deletions
2
.github/BOTMETA.yml
vendored
2
.github/BOTMETA.yml
vendored
|
@ -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:
|
||||
|
|
|
@ -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"),
|
||||
|
|
213
plugins/modules/pacemaker_stonith.py
Normal file
213
plugins/modules/pacemaker_stonith.py
Normal file
|
@ -0,0 +1,213 @@
|
|||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright (c) 2025, 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
|
||||
|
||||
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.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:
|
||||
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_options:
|
||||
description:
|
||||
- Specify the STONITH option to create.
|
||||
type: list
|
||||
elements: str
|
||||
default: []
|
||||
stonith_operations:
|
||||
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_options:
|
||||
description:
|
||||
- Operation options to associate with action.
|
||||
type: list
|
||||
elements: str
|
||||
stonith_metas:
|
||||
description:
|
||||
- List of metadata 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_options:
|
||||
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 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 = '''
|
||||
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_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'),
|
||||
)),
|
||||
stonith_metas=dict(type='list', elements='str'),
|
||||
stonith_argument=dict(type='dict', options=dict(
|
||||
argument_action=dict(type='str', choices=['before', 'after', 'group']),
|
||||
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_options'])],
|
||||
supports_check_mode=True
|
||||
)
|
||||
|
||||
def __init_module__(self):
|
||||
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)
|
||||
|
||||
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:
|
||||
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('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])])
|
||||
|
||||
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('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(
|
||||
'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(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('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('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():
|
||||
PacemakerStonith.execute()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
19
tests/unit/plugins/modules/test_pacemaker_stonith.py
Normal file
19
tests/unit/plugins/modules/test_pacemaker_stonith.py
Normal file
|
@ -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])
|
216
tests/unit/plugins/modules/test_pacemaker_stonith.yaml
Normal file
216
tests/unit/plugins/modules/test_pacemaker_stonith.yaml
Normal file
|
@ -0,0 +1,216 @@
|
|||
# -*- 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_options:
|
||||
- "pcmk_host_list=f1"
|
||||
stonith_operations:
|
||||
- operation_action: monitor
|
||||
operation_options:
|
||||
- "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_options:
|
||||
- "pcmk_host_list=f1"
|
||||
stonith_operations:
|
||||
- operation_action: monitor
|
||||
operation_options:
|
||||
- "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"
|
||||
- command: ["/testbin/pcs", stonith, status, virtual-stonith]
|
||||
environ: *env-def
|
||||
rc: 1
|
||||
out: ""
|
||||
err: ""
|
||||
- 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"
|
||||
- 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
|
||||
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: ""
|
Loading…
Add table
Add a link
Reference in a new issue