mirror of
https://github.com/ansible-collections/community.general.git
synced 2024-09-14 20:13:21 +02:00
lvg_rename: New module to support VG renaming (#6721)
* lvg_rename: New module to support VG renaming * Remove vg option aliases Fix YAML boolean case-formatting Co-authored-by: Felix Fontein <felix@fontein.de> --------- Co-authored-by: Felix Fontein <felix@fontein.de>
This commit is contained in:
parent
5d9eb8be95
commit
4871140696
9 changed files with 580 additions and 0 deletions
2
.github/BOTMETA.yml
vendored
2
.github/BOTMETA.yml
vendored
|
@ -757,6 +757,8 @@ files:
|
||||||
maintainers: nerzhul
|
maintainers: nerzhul
|
||||||
$modules/lvg.py:
|
$modules/lvg.py:
|
||||||
maintainers: abulimov
|
maintainers: abulimov
|
||||||
|
$modules/lvg_rename.py:
|
||||||
|
maintainers: lszomor
|
||||||
$modules/lvol.py:
|
$modules/lvol.py:
|
||||||
maintainers: abulimov jhoekx zigaSRC unkaputtbar112
|
maintainers: abulimov jhoekx zigaSRC unkaputtbar112
|
||||||
$modules/lxc_container.py:
|
$modules/lxc_container.py:
|
||||||
|
|
170
plugins/modules/lvg_rename.py
Normal file
170
plugins/modules/lvg_rename.py
Normal file
|
@ -0,0 +1,170 @@
|
||||||
|
#!/usr/bin/python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
# Copyright (c) Contributors to the 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
|
||||||
|
|
||||||
|
from __future__ import absolute_import, division, print_function
|
||||||
|
__metaclass__ = type
|
||||||
|
|
||||||
|
DOCUMENTATION = r'''
|
||||||
|
---
|
||||||
|
author:
|
||||||
|
- Laszlo Szomor (@lszomor)
|
||||||
|
module: lvg_rename
|
||||||
|
short_description: Renames LVM volume groups
|
||||||
|
description:
|
||||||
|
- This module renames volume groups using the C(vgchange) command.
|
||||||
|
extends_documentation_fragment:
|
||||||
|
- community.general.attributes
|
||||||
|
attributes:
|
||||||
|
check_mode:
|
||||||
|
support: full
|
||||||
|
diff_mode:
|
||||||
|
support: full
|
||||||
|
version_added: 7.1.0
|
||||||
|
options:
|
||||||
|
vg:
|
||||||
|
description:
|
||||||
|
- The name or UUID of the source VG.
|
||||||
|
- See V(vgrename(8\)) for valid values.
|
||||||
|
type: str
|
||||||
|
required: true
|
||||||
|
vg_new:
|
||||||
|
description:
|
||||||
|
- The new name of the VG.
|
||||||
|
- See V(lvm(8\)) for valid names.
|
||||||
|
type: str
|
||||||
|
required: true
|
||||||
|
seealso:
|
||||||
|
- module: community.general.lvg
|
||||||
|
notes:
|
||||||
|
- This module does not modify VG renaming-related configurations like C(fstab) entries or boot parameters.
|
||||||
|
'''
|
||||||
|
|
||||||
|
EXAMPLES = r'''
|
||||||
|
- name: Rename a VG by name
|
||||||
|
community.general.lvg_rename:
|
||||||
|
vg: vg_orig_name
|
||||||
|
vg_new: vg_new_name
|
||||||
|
|
||||||
|
- name: Rename a VG by UUID
|
||||||
|
community.general.lvg_rename:
|
||||||
|
vg_uuid: SNgd0Q-rPYa-dPB8-U1g6-4WZI-qHID-N7y9Vj
|
||||||
|
vg_new: vg_new_name
|
||||||
|
'''
|
||||||
|
|
||||||
|
from ansible.module_utils.basic import AnsibleModule
|
||||||
|
|
||||||
|
argument_spec = dict(
|
||||||
|
vg=dict(type='str', required=True,),
|
||||||
|
vg_new=dict(type='str', required=True,),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class LvgRename(object):
|
||||||
|
def __init__(self, module):
|
||||||
|
'''
|
||||||
|
Orchestrates the lvg_rename module logic.
|
||||||
|
|
||||||
|
:param module: An AnsibleModule instance.
|
||||||
|
'''
|
||||||
|
self.module = module
|
||||||
|
self.result = {'changed': False}
|
||||||
|
self.vg_list = []
|
||||||
|
self._load_params()
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
"""Performs the module logic."""
|
||||||
|
|
||||||
|
self._load_vg_list()
|
||||||
|
|
||||||
|
old_vg_exists = self._is_vg_exists(vg=self.vg)
|
||||||
|
new_vg_exists = self._is_vg_exists(vg=self.vg_new)
|
||||||
|
|
||||||
|
if old_vg_exists:
|
||||||
|
if new_vg_exists:
|
||||||
|
self.module.fail_json(msg='The new VG name (%s) is already in use.' % (self.vg_new))
|
||||||
|
else:
|
||||||
|
self._rename_vg()
|
||||||
|
else:
|
||||||
|
if new_vg_exists:
|
||||||
|
self.result['msg'] = 'The new VG (%s) already exists, nothing to do.' % (self.vg_new)
|
||||||
|
self.module.exit_json(**self.result)
|
||||||
|
else:
|
||||||
|
self.module.fail_json(msg='Both current (%s) and new (%s) VG are missing.' % (self.vg, self.vg_new))
|
||||||
|
|
||||||
|
self.module.exit_json(**self.result)
|
||||||
|
|
||||||
|
def _load_params(self):
|
||||||
|
"""Load the parameters from the module."""
|
||||||
|
|
||||||
|
self.vg = self.module.params['vg']
|
||||||
|
self.vg_new = self.module.params['vg_new']
|
||||||
|
|
||||||
|
def _load_vg_list(self):
|
||||||
|
"""Load the VGs from the system."""
|
||||||
|
|
||||||
|
vgs_cmd = self.module.get_bin_path('vgs', required=True)
|
||||||
|
vgs_cmd_with_opts = [vgs_cmd, '--noheadings', '--separator', ';', '-o', 'vg_name,vg_uuid']
|
||||||
|
dummy, vg_raw_list, dummy = self.module.run_command(vgs_cmd_with_opts, check_rc=True)
|
||||||
|
|
||||||
|
for vg_info in vg_raw_list.splitlines():
|
||||||
|
vg_name, vg_uuid = vg_info.strip().split(';')
|
||||||
|
self.vg_list.append(vg_name)
|
||||||
|
self.vg_list.append(vg_uuid)
|
||||||
|
|
||||||
|
def _is_vg_exists(self, vg):
|
||||||
|
'''
|
||||||
|
Checks VG existence by name or UUID. It removes the '/dev/' prefix before checking.
|
||||||
|
|
||||||
|
:param vg: A string with the name or UUID of the VG.
|
||||||
|
:returns: A boolean indicates whether the VG exists or not.
|
||||||
|
'''
|
||||||
|
|
||||||
|
vg_found = False
|
||||||
|
dev_prefix = '/dev/'
|
||||||
|
|
||||||
|
if vg.startswith(dev_prefix):
|
||||||
|
vg_id = vg[len(dev_prefix):]
|
||||||
|
else:
|
||||||
|
vg_id = vg
|
||||||
|
|
||||||
|
vg_found = vg_id in self.vg_list
|
||||||
|
|
||||||
|
return vg_found
|
||||||
|
|
||||||
|
def _rename_vg(self):
|
||||||
|
"""Renames the volume group."""
|
||||||
|
|
||||||
|
vgrename_cmd = self.module.get_bin_path('vgrename', required=True)
|
||||||
|
|
||||||
|
if self.module._diff:
|
||||||
|
self.result['diff'] = {'before': {'vg': self.vg}, 'after': {'vg': self.vg_new}}
|
||||||
|
|
||||||
|
if self.module.check_mode:
|
||||||
|
self.result['msg'] = "Running in check mode. The module would rename VG %s to %s." % (self.vg, self.vg_new)
|
||||||
|
self.result['changed'] = True
|
||||||
|
else:
|
||||||
|
vgrename_cmd_with_opts = [vgrename_cmd, self.vg, self.vg_new]
|
||||||
|
dummy, vg_rename_out, dummy = self.module.run_command(vgrename_cmd_with_opts, check_rc=True)
|
||||||
|
|
||||||
|
self.result['msg'] = vg_rename_out
|
||||||
|
self.result['changed'] = True
|
||||||
|
|
||||||
|
|
||||||
|
def setup_module_object():
|
||||||
|
module = AnsibleModule(argument_spec=argument_spec,
|
||||||
|
supports_check_mode=True)
|
||||||
|
return module
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
module = setup_module_object()
|
||||||
|
lvg_rename = LvgRename(module=module)
|
||||||
|
lvg_rename.run()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
13
tests/integration/targets/lvg_rename/aliases
Normal file
13
tests/integration/targets/lvg_rename/aliases
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
# Copyright (c) Contributors to the Ansible project
|
||||||
|
# Based on the integraton test for the lvg module
|
||||||
|
# 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
|
||||||
|
|
||||||
|
azp/posix/1
|
||||||
|
azp/posix/vm
|
||||||
|
destructive
|
||||||
|
needs/privileged
|
||||||
|
skip/aix
|
||||||
|
skip/freebsd
|
||||||
|
skip/osx
|
||||||
|
skip/macos
|
9
tests/integration/targets/lvg_rename/meta/main.yml
Normal file
9
tests/integration/targets/lvg_rename/meta/main.yml
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
---
|
||||||
|
# Copyright (c) Ansible Project
|
||||||
|
# Based on the integraton test for the lvg module
|
||||||
|
# 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
|
||||||
|
|
||||||
|
dependencies:
|
||||||
|
- setup_pkg_mgr
|
||||||
|
- setup_remote_tmp_dir
|
25
tests/integration/targets/lvg_rename/tasks/main.yml
Normal file
25
tests/integration/targets/lvg_rename/tasks/main.yml
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
---
|
||||||
|
####################################################################
|
||||||
|
# WARNING: These are designed specifically for Ansible tests #
|
||||||
|
# and should not be used as examples of how to write Ansible roles #
|
||||||
|
####################################################################
|
||||||
|
|
||||||
|
# Copyright (c) Contributors to the Ansible project
|
||||||
|
# Based on the integraton test for the lvg module
|
||||||
|
# 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: Install required packages (Linux)
|
||||||
|
when: ansible_system == 'Linux'
|
||||||
|
ansible.builtin.package:
|
||||||
|
name: lvm2
|
||||||
|
state: present
|
||||||
|
|
||||||
|
- name: Test lvg_rename module
|
||||||
|
block:
|
||||||
|
- import_tasks: setup.yml
|
||||||
|
|
||||||
|
- import_tasks: test.yml
|
||||||
|
|
||||||
|
always:
|
||||||
|
- import_tasks: teardown.yml
|
50
tests/integration/targets/lvg_rename/tasks/setup.yml
Normal file
50
tests/integration/targets/lvg_rename/tasks/setup.yml
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
---
|
||||||
|
# Copyright (c) Contributors to the Ansible project
|
||||||
|
# Based on the integraton test for the lvg module
|
||||||
|
# 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: Create files to use as disk devices
|
||||||
|
with_sequence: 'count=2'
|
||||||
|
ansible.builtin.command:
|
||||||
|
cmd: "dd if=/dev/zero of={{ remote_tmp_dir }}/img{{ item }} bs=1M count=10"
|
||||||
|
creates: "{{ remote_tmp_dir }}/img{{ item }}"
|
||||||
|
|
||||||
|
- name: Show next free loop device
|
||||||
|
ansible.builtin.command:
|
||||||
|
cmd: "losetup -f"
|
||||||
|
changed_when: false
|
||||||
|
register: loop_device1
|
||||||
|
|
||||||
|
- name: "Create loop device for file {{ remote_tmp_dir }}/img1"
|
||||||
|
ansible.builtin.command:
|
||||||
|
cmd: "losetup -f {{ remote_tmp_dir }}/img1"
|
||||||
|
changed_when: true
|
||||||
|
|
||||||
|
- name: Show next free loop device
|
||||||
|
ansible.builtin.command:
|
||||||
|
cmd: "losetup -f"
|
||||||
|
changed_when: false
|
||||||
|
register: loop_device2
|
||||||
|
|
||||||
|
- name: "Create loop device for file {{ remote_tmp_dir }}/img2"
|
||||||
|
ansible.builtin.command:
|
||||||
|
cmd: "losetup -f {{ remote_tmp_dir }}/img2"
|
||||||
|
changed_when: true
|
||||||
|
|
||||||
|
- name: Affect name on disk to work on
|
||||||
|
ansible.builtin.set_fact:
|
||||||
|
loop_device1: "{{ loop_device1.stdout }}"
|
||||||
|
loop_device2: "{{ loop_device2.stdout }}"
|
||||||
|
|
||||||
|
- name: "Create test volume group testvg on {{ loop_device1 }}"
|
||||||
|
community.general.lvg:
|
||||||
|
vg: "testvg"
|
||||||
|
state: present
|
||||||
|
pvs: "{{ loop_device1 }}"
|
||||||
|
|
||||||
|
- name: "Create test volume group testvg2 on {{ loop_device2 }}"
|
||||||
|
community.general.lvg:
|
||||||
|
vg: "testvg2"
|
||||||
|
state: present
|
||||||
|
pvs: "{{ loop_device2 }}"
|
46
tests/integration/targets/lvg_rename/tasks/teardown.yml
Normal file
46
tests/integration/targets/lvg_rename/tasks/teardown.yml
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
---
|
||||||
|
# Copyright (c) Contributors to the Ansible project
|
||||||
|
# Based on the integraton test for the lvg module
|
||||||
|
# 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: Collect test volume groups
|
||||||
|
ansible.builtin.command:
|
||||||
|
cmd: "pvs --noheadings -ovg_name {{ loop_device1 | default('') }} {{ loop_device2 | default('') }}"
|
||||||
|
register: test_vgs_output
|
||||||
|
changed_when: false
|
||||||
|
|
||||||
|
- name: Remove test volume groups
|
||||||
|
loop: "{{ test_vgs_output.stdout_lines }}"
|
||||||
|
loop_control:
|
||||||
|
label: "{{ item | trim }}"
|
||||||
|
community.general.lvg:
|
||||||
|
vg: "{{ item | trim }}"
|
||||||
|
state: absent
|
||||||
|
|
||||||
|
- name: Remove lvmdevices
|
||||||
|
loop:
|
||||||
|
- "{{ loop_device1 | default('') }}"
|
||||||
|
- "{{ loop_device2 | default('') }}"
|
||||||
|
when:
|
||||||
|
- item | length > 0
|
||||||
|
ansible.builtin.command:
|
||||||
|
cmd: "lvmdevices --deldev {{ item }}"
|
||||||
|
failed_when: false
|
||||||
|
changed_when: true
|
||||||
|
|
||||||
|
- name: Detach loop devices
|
||||||
|
loop:
|
||||||
|
- "{{ loop_device1 | default('') }}"
|
||||||
|
- "{{ loop_device2 | default('') }}"
|
||||||
|
when:
|
||||||
|
- item | length > 0
|
||||||
|
ansible.builtin.command:
|
||||||
|
cmd: "losetup -d {{ item }}"
|
||||||
|
changed_when: true
|
||||||
|
|
||||||
|
- name: Remove device files
|
||||||
|
with_sequence: 'count=2'
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: "{{ remote_tmp_dir }}/img{{ item }}"
|
||||||
|
state: absent
|
105
tests/integration/targets/lvg_rename/tasks/test.yml
Normal file
105
tests/integration/targets/lvg_rename/tasks/test.yml
Normal file
|
@ -0,0 +1,105 @@
|
||||||
|
---
|
||||||
|
# Copyright (c) Contributors to the 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: Rename a VG in check mode
|
||||||
|
community.general.lvg_rename:
|
||||||
|
vg: testvg
|
||||||
|
vg_new: testvg_renamed
|
||||||
|
check_mode: true
|
||||||
|
register: check_mode_vg_rename
|
||||||
|
|
||||||
|
- name: Check if testvg still exists
|
||||||
|
ansible.builtin.command:
|
||||||
|
cmd: vgs testvg
|
||||||
|
changed_when: false
|
||||||
|
|
||||||
|
- name: Assert that renaming a VG is changed - check mode
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- check_mode_vg_rename is changed
|
||||||
|
|
||||||
|
- name: Rename testvg to testvg_renamed
|
||||||
|
community.general.lvg_rename:
|
||||||
|
vg: testvg
|
||||||
|
vg_new: testvg_renamed
|
||||||
|
register: vg_renamed
|
||||||
|
|
||||||
|
- name: Assert that renaming a VG is changed
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- vg_renamed is changed
|
||||||
|
|
||||||
|
- name: Check if testvg does not exists
|
||||||
|
ansible.builtin.command:
|
||||||
|
cmd: vgs testvg
|
||||||
|
register: check_testvg_existence_result
|
||||||
|
failed_when: check_testvg_existence_result.rc == 0
|
||||||
|
changed_when: false
|
||||||
|
|
||||||
|
- name: Check if testvg_renamed exists
|
||||||
|
ansible.builtin.command:
|
||||||
|
cmd: vgs testvg_renamed
|
||||||
|
changed_when: false
|
||||||
|
|
||||||
|
- name: Rename testvg to testvg_renamed again for testing idempotency - check mode
|
||||||
|
community.general.lvg_rename:
|
||||||
|
vg: testvg
|
||||||
|
vg_new: testvg_renamed
|
||||||
|
check_mode: true
|
||||||
|
register: check_mode_vg_renamed_again
|
||||||
|
|
||||||
|
- name: Rename testvg to testvg_renamed again for testing idempotency
|
||||||
|
community.general.lvg_rename:
|
||||||
|
vg: testvg
|
||||||
|
vg_new: testvg_renamed
|
||||||
|
register: vg_renamed_again
|
||||||
|
|
||||||
|
- name: Assert that renaming a VG again is not changed
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- check_mode_vg_renamed_again is not changed
|
||||||
|
- vg_renamed_again is not changed
|
||||||
|
|
||||||
|
- name: Rename a non-existing VG - check mode
|
||||||
|
community.general.lvg_rename:
|
||||||
|
vg: testvg
|
||||||
|
vg_new: testvg_ne
|
||||||
|
check_mode: true
|
||||||
|
ignore_errors: true
|
||||||
|
register: check_mode_ne_vg_rename
|
||||||
|
|
||||||
|
- name: Rename a non-existing VG
|
||||||
|
community.general.lvg_rename:
|
||||||
|
vg: testvg
|
||||||
|
vg_new: testvg_ne
|
||||||
|
ignore_errors: true
|
||||||
|
register: ne_vg_rename
|
||||||
|
|
||||||
|
- name: Assert that renaming a no-existing VG failed
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- check_mode_ne_vg_rename is failed
|
||||||
|
- ne_vg_rename is failed
|
||||||
|
|
||||||
|
- name: Rename testvg_renamed to the existing testvg2 name - check mode
|
||||||
|
community.general.lvg_rename:
|
||||||
|
vg: testvg_renamed
|
||||||
|
vg_new: testvg2
|
||||||
|
check_mode: true
|
||||||
|
ignore_errors: true
|
||||||
|
register: check_mode_vg_rename_collision
|
||||||
|
|
||||||
|
- name: Rename testvg_renamed to the existing testvg2 name
|
||||||
|
community.general.lvg_rename:
|
||||||
|
vg: testvg_renamed
|
||||||
|
vg_new: testvg2
|
||||||
|
ignore_errors: true
|
||||||
|
register: vg_rename_collision
|
||||||
|
|
||||||
|
- name: Assert that renaming to an existing VG name failed
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- check_mode_vg_rename_collision is failed
|
||||||
|
- vg_rename_collision is failed
|
160
tests/unit/plugins/modules/test_lvg_rename.py
Normal file
160
tests/unit/plugins/modules/test_lvg_rename.py
Normal file
|
@ -0,0 +1,160 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Copyright (c) Contributors to the 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
|
||||||
|
|
||||||
|
from __future__ import absolute_import, division, print_function
|
||||||
|
__metaclass__ = type
|
||||||
|
|
||||||
|
from ansible_collections.community.general.plugins.modules import lvg_rename
|
||||||
|
from ansible_collections.community.general.tests.unit.compat.mock import patch
|
||||||
|
from ansible_collections.community.general.tests.unit.plugins.modules.utils import (
|
||||||
|
AnsibleFailJson, AnsibleExitJson, ModuleTestCase, set_module_args)
|
||||||
|
|
||||||
|
|
||||||
|
VGS_OUTPUT = '''\
|
||||||
|
vg_data_testhost1;XKZ5gn-YhWY-NlrT-QCFN-qmMG-VGT9-7uOmex
|
||||||
|
vg_sys_testhost2;xgy2SJ-YlYd-fde2-e3oG-zdXL-0xGf-ihqG2H
|
||||||
|
'''
|
||||||
|
|
||||||
|
|
||||||
|
class TestLvgRename(ModuleTestCase):
|
||||||
|
"""Tests for lvg_rename internals"""
|
||||||
|
module = lvg_rename
|
||||||
|
module_path = 'ansible_collections.community.general.plugins.modules.lvg_rename'
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
"""Prepare mocks for module testing"""
|
||||||
|
super(TestLvgRename, self).setUp()
|
||||||
|
|
||||||
|
self.mock_run_responses = {}
|
||||||
|
|
||||||
|
patched_module_get_bin_path = patch('%s.AnsibleModule.get_bin_path' % (self.module_path))
|
||||||
|
self.mock_module_get_bin_path = patched_module_get_bin_path.start()
|
||||||
|
self.mock_module_get_bin_path.return_value = '/mocpath'
|
||||||
|
self.addCleanup(patched_module_get_bin_path.stop)
|
||||||
|
|
||||||
|
patched_module_run_command = patch('%s.AnsibleModule.run_command' % (self.module_path))
|
||||||
|
self.mock_module_run_command = patched_module_run_command.start()
|
||||||
|
self.addCleanup(patched_module_run_command.stop)
|
||||||
|
|
||||||
|
def test_vg_not_found_by_name(self):
|
||||||
|
"""When the VG by the specified by vg name not found, the module should exit with error"""
|
||||||
|
failed = True
|
||||||
|
self.mock_module_run_command.side_effect = [(0, VGS_OUTPUT, '')]
|
||||||
|
expected_msg = 'Both current (vg_missing) and new (vg_data_testhost2) VG are missing.'
|
||||||
|
|
||||||
|
module_args = {
|
||||||
|
'vg': 'vg_missing',
|
||||||
|
'vg_new': 'vg_data_testhost2',
|
||||||
|
}
|
||||||
|
set_module_args(args=module_args)
|
||||||
|
|
||||||
|
with self.assertRaises(AnsibleFailJson) as result:
|
||||||
|
self.module.main()
|
||||||
|
|
||||||
|
self.assertEqual(len(self.mock_module_run_command.mock_calls), 1)
|
||||||
|
self.assertIs(result.exception.args[0]['failed'], failed)
|
||||||
|
self.assertEqual(result.exception.args[0]['msg'], expected_msg)
|
||||||
|
|
||||||
|
def test_vg_not_found_by_uuid(self):
|
||||||
|
"""When the VG by the specified vg UUID not found, the module should exit with error"""
|
||||||
|
failed = True
|
||||||
|
self.mock_module_run_command.side_effect = [(0, VGS_OUTPUT, '')]
|
||||||
|
expected_msg = 'Both current (Yfj4YG-c8nI-z7w5-B7Fw-i2eM-HqlF-ApFVp0) and new (vg_data_testhost2) VG are missing.'
|
||||||
|
|
||||||
|
module_args = {
|
||||||
|
'vg': 'Yfj4YG-c8nI-z7w5-B7Fw-i2eM-HqlF-ApFVp0',
|
||||||
|
'vg_new': 'vg_data_testhost2',
|
||||||
|
}
|
||||||
|
set_module_args(args=module_args)
|
||||||
|
|
||||||
|
with self.assertRaises(AnsibleFailJson) as result:
|
||||||
|
self.module.main()
|
||||||
|
|
||||||
|
self.assertEqual(len(self.mock_module_run_command.mock_calls), 1)
|
||||||
|
self.assertIs(result.exception.args[0]['failed'], failed)
|
||||||
|
self.assertEqual(result.exception.args[0]['msg'], expected_msg)
|
||||||
|
|
||||||
|
def test_vg_and_vg_new_both_exists(self):
|
||||||
|
"""When a VG found for both vg and vg_new options, the module should exit with error"""
|
||||||
|
failed = True
|
||||||
|
self.mock_module_run_command.side_effect = [(0, VGS_OUTPUT, '')]
|
||||||
|
expected_msg = 'The new VG name (vg_sys_testhost2) is already in use.'
|
||||||
|
|
||||||
|
module_args = {
|
||||||
|
'vg': 'vg_data_testhost1',
|
||||||
|
'vg_new': 'vg_sys_testhost2',
|
||||||
|
}
|
||||||
|
set_module_args(args=module_args)
|
||||||
|
|
||||||
|
with self.assertRaises(AnsibleFailJson) as result:
|
||||||
|
self.module.main()
|
||||||
|
|
||||||
|
self.assertEqual(len(self.mock_module_run_command.mock_calls), 1)
|
||||||
|
self.assertIs(result.exception.args[0]['failed'], failed)
|
||||||
|
self.assertEqual(result.exception.args[0]['msg'], expected_msg)
|
||||||
|
|
||||||
|
def test_vg_needs_renaming(self):
|
||||||
|
"""When the VG found for vg option and there is no VG for vg_new option,
|
||||||
|
the module should call vgrename"""
|
||||||
|
changed = True
|
||||||
|
self.mock_module_run_command.side_effect = [
|
||||||
|
(0, VGS_OUTPUT, ''),
|
||||||
|
(0, ' Volume group "vg_data_testhost1" successfully renamed to "vg_data_testhost2"', '')
|
||||||
|
]
|
||||||
|
expected_msg = ' Volume group "vg_data_testhost1" successfully renamed to "vg_data_testhost2"'
|
||||||
|
|
||||||
|
module_args = {
|
||||||
|
'vg': '/dev/vg_data_testhost1',
|
||||||
|
'vg_new': 'vg_data_testhost2',
|
||||||
|
}
|
||||||
|
set_module_args(args=module_args)
|
||||||
|
|
||||||
|
with self.assertRaises(AnsibleExitJson) as result:
|
||||||
|
self.module.main()
|
||||||
|
|
||||||
|
self.assertEqual(len(self.mock_module_run_command.mock_calls), 2)
|
||||||
|
self.assertIs(result.exception.args[0]['changed'], changed)
|
||||||
|
self.assertEqual(result.exception.args[0]['msg'], expected_msg)
|
||||||
|
|
||||||
|
def test_vg_needs_renaming_in_check_mode(self):
|
||||||
|
"""When running in check mode and the VG found for vg option and there is no VG for vg_new option,
|
||||||
|
the module should not call vgrename"""
|
||||||
|
changed = True
|
||||||
|
self.mock_module_run_command.side_effect = [(0, VGS_OUTPUT, '')]
|
||||||
|
expected_msg = 'Running in check mode. The module would rename VG /dev/vg_data_testhost1 to vg_data_testhost2.'
|
||||||
|
|
||||||
|
module_args = {
|
||||||
|
'vg': '/dev/vg_data_testhost1',
|
||||||
|
'vg_new': 'vg_data_testhost2',
|
||||||
|
'_ansible_check_mode': True,
|
||||||
|
}
|
||||||
|
set_module_args(args=module_args)
|
||||||
|
|
||||||
|
with self.assertRaises(AnsibleExitJson) as result:
|
||||||
|
self.module.main()
|
||||||
|
|
||||||
|
self.assertEqual(len(self.mock_module_run_command.mock_calls), 1)
|
||||||
|
self.assertIs(result.exception.args[0]['changed'], changed)
|
||||||
|
self.assertEqual(result.exception.args[0]['msg'], expected_msg)
|
||||||
|
|
||||||
|
def test_vg_needs_no_renaming(self):
|
||||||
|
"""When the VG not found for vg option and the VG found for vg_new option,
|
||||||
|
the module should not call vgrename"""
|
||||||
|
changed = False
|
||||||
|
self.mock_module_run_command.side_effect = [(0, VGS_OUTPUT, '')]
|
||||||
|
expected_msg = 'The new VG (vg_data_testhost1) already exists, nothing to do.'
|
||||||
|
|
||||||
|
module_args = {
|
||||||
|
'vg': 'vg_data_testhostX',
|
||||||
|
'vg_new': 'vg_data_testhost1',
|
||||||
|
}
|
||||||
|
set_module_args(args=module_args)
|
||||||
|
|
||||||
|
with self.assertRaises(AnsibleExitJson) as result:
|
||||||
|
self.module.main()
|
||||||
|
|
||||||
|
self.assertEqual(len(self.mock_module_run_command.mock_calls), 1)
|
||||||
|
self.assertIs(result.exception.args[0]['changed'], changed)
|
||||||
|
self.assertEqual(result.exception.args[0]['msg'], expected_msg)
|
Loading…
Reference in a new issue