mirror of
https://github.com/ansible-collections/community.general.git
synced 2025-08-04 13:14:24 -07:00
lvm_pv_move_data: new module (#10416)
* Added lvm_pv_move_data module * Removed trailing whitespace * Decreased loop devices file size * Remove test VG if exists * Force remove test VG if exists * Renamed test VG and LV names * Updated assert conditions * Added .ansible to .gitignore * Force extending VG * Wiping LVM metadata from PVs before creating VG * Clean FS, LV, VG and PSs before run * Migrated to CmdRunner * Added more detailed info in case of failure and cosmetic changes * Remove redundant params from CmdRunner call * Updates the RETURN documentation block to properly specify the return type of the 'actions' field: - Changes return status from 'always' to 'success' - Adds missing 'elements: str' type specification
This commit is contained in:
parent
658af61e17
commit
e91e2ef6f8
10 changed files with 487 additions and 0 deletions
2
.github/BOTMETA.yml
vendored
2
.github/BOTMETA.yml
vendored
|
@ -903,6 +903,8 @@ files:
|
||||||
maintainers: abulimov
|
maintainers: abulimov
|
||||||
$modules/lvm_pv.py:
|
$modules/lvm_pv.py:
|
||||||
maintainers: klention
|
maintainers: klention
|
||||||
|
$modules/lvm_pv_move_data.py:
|
||||||
|
maintainers: klention
|
||||||
$modules/lvg_rename.py:
|
$modules/lvg_rename.py:
|
||||||
maintainers: lszomor
|
maintainers: lszomor
|
||||||
$modules/lvol.py:
|
$modules/lvol.py:
|
||||||
|
|
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -530,3 +530,4 @@ tests/integration/cloud-config-*.ini
|
||||||
|
|
||||||
# VSCode specific extensions
|
# VSCode specific extensions
|
||||||
.vscode/settings.json
|
.vscode/settings.json
|
||||||
|
.ansible
|
||||||
|
|
220
plugins/modules/lvm_pv_move_data.py
Normal file
220
plugins/modules/lvm_pv_move_data.py
Normal file
|
@ -0,0 +1,220 @@
|
||||||
|
#!/usr/bin/python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
# Copyright (c) 2025, Klention Mali <klention@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 = r"""
|
||||||
|
module: lvm_pv_move_data
|
||||||
|
short_description: Move data between LVM Physical Volumes (PVs)
|
||||||
|
version_added: "11.2.0"
|
||||||
|
description:
|
||||||
|
- Moves data from one LVM Physical Volume (PV) to another.
|
||||||
|
author:
|
||||||
|
- Klention Mali (@klention)
|
||||||
|
options:
|
||||||
|
source:
|
||||||
|
description:
|
||||||
|
- Path to the source block device to move data from.
|
||||||
|
- Must be an existing PV.
|
||||||
|
type: path
|
||||||
|
required: true
|
||||||
|
destination:
|
||||||
|
description:
|
||||||
|
- Path to the destination block device to move data to.
|
||||||
|
- Must be an existing PV with enough free space.
|
||||||
|
type: path
|
||||||
|
required: true
|
||||||
|
auto_answer:
|
||||||
|
description:
|
||||||
|
- Answer yes to all prompts automatically.
|
||||||
|
type: bool
|
||||||
|
default: false
|
||||||
|
atomic:
|
||||||
|
description:
|
||||||
|
- Makes the C(pvmove) operation atomic, ensuring that all affected LVs are moved to the destination PV,
|
||||||
|
or none are if the operation is aborted.
|
||||||
|
type: bool
|
||||||
|
default: true
|
||||||
|
autobackup:
|
||||||
|
description:
|
||||||
|
- Automatically backup metadata before changes (strongly advised!).
|
||||||
|
type: bool
|
||||||
|
default: true
|
||||||
|
requirements:
|
||||||
|
- LVM2 utilities
|
||||||
|
- Both O(source) and O(destination) devices must exist, and the PVs must be in the same volume group.
|
||||||
|
- The O(destination) PV must have enough free space to accommodate the O(source) PV's allocated extents.
|
||||||
|
- Verbosity is automatically controlled by Ansible's verbosity level (using multiple C(-v) flags).
|
||||||
|
"""
|
||||||
|
|
||||||
|
EXAMPLES = r"""
|
||||||
|
- name: Moving data from /dev/sdb to /dev/sdc
|
||||||
|
community.general.lvm_pv_move_data:
|
||||||
|
source: /dev/sdb
|
||||||
|
destination: /dev/sdc
|
||||||
|
"""
|
||||||
|
|
||||||
|
RETURN = r"""
|
||||||
|
actions:
|
||||||
|
description: List of actions performed during module execution.
|
||||||
|
returned: success
|
||||||
|
type: list
|
||||||
|
elements: str
|
||||||
|
sample: [
|
||||||
|
"moved data from /dev/sdb to /dev/sdc",
|
||||||
|
"no allocated extents to move",
|
||||||
|
"would move data from /dev/sdb to /dev/sdc"
|
||||||
|
]
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
import os
|
||||||
|
from ansible.module_utils.basic import AnsibleModule
|
||||||
|
from ansible_collections.community.general.plugins.module_utils.cmd_runner import CmdRunner, cmd_runner_fmt
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
module = AnsibleModule(
|
||||||
|
argument_spec=dict(
|
||||||
|
source=dict(type='path', required=True),
|
||||||
|
destination=dict(type='path', required=True),
|
||||||
|
auto_answer=dict(type='bool', default=False),
|
||||||
|
atomic=dict(type='bool', default=True),
|
||||||
|
autobackup=dict(type='bool', default=True),
|
||||||
|
),
|
||||||
|
supports_check_mode=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
pvs_runner = CmdRunner(
|
||||||
|
module,
|
||||||
|
command="pvs",
|
||||||
|
arg_formats=dict(
|
||||||
|
noheadings=cmd_runner_fmt.as_fixed("--noheadings"),
|
||||||
|
readonly=cmd_runner_fmt.as_fixed("--readonly"),
|
||||||
|
vg_name=cmd_runner_fmt.as_fixed("-o", "vg_name"),
|
||||||
|
pv_pe_alloc_count=cmd_runner_fmt.as_fixed("-o", "pv_pe_alloc_count"),
|
||||||
|
pv_pe_count=cmd_runner_fmt.as_fixed("-o", "pv_pe_count"),
|
||||||
|
device=cmd_runner_fmt.as_list(),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
source = module.params['source']
|
||||||
|
destination = module.params['destination']
|
||||||
|
changed = False
|
||||||
|
actions = []
|
||||||
|
result = {'changed': False}
|
||||||
|
|
||||||
|
# Validate device existence
|
||||||
|
if not os.path.exists(source):
|
||||||
|
module.fail_json(msg="Source device %s not found" % source)
|
||||||
|
if not os.path.exists(destination):
|
||||||
|
module.fail_json(msg="Destination device %s not found" % destination)
|
||||||
|
if source == destination:
|
||||||
|
module.fail_json(msg="Source and destination devices must be different")
|
||||||
|
|
||||||
|
def run_pvs_command(arguments, device):
|
||||||
|
with pvs_runner(arguments) as ctx:
|
||||||
|
rc, out, err = ctx.run(device=device)
|
||||||
|
if rc != 0:
|
||||||
|
module.fail_json(
|
||||||
|
msg="Command failed: %s" % err,
|
||||||
|
stdout=out,
|
||||||
|
stderr=err,
|
||||||
|
rc=rc,
|
||||||
|
cmd=ctx.cmd,
|
||||||
|
arguments=arguments,
|
||||||
|
device=device,
|
||||||
|
)
|
||||||
|
return out.strip()
|
||||||
|
|
||||||
|
def is_pv(device):
|
||||||
|
with pvs_runner("noheadings readonly device", check_rc=False) as ctx:
|
||||||
|
rc, out, err = ctx.run(device=device)
|
||||||
|
return rc == 0
|
||||||
|
|
||||||
|
if not is_pv(source):
|
||||||
|
module.fail_json(msg="Source device %s is not a PV" % source)
|
||||||
|
if not is_pv(destination):
|
||||||
|
module.fail_json(msg="Destination device %s is not a PV" % destination)
|
||||||
|
|
||||||
|
vg_src = run_pvs_command("noheadings vg_name device", source)
|
||||||
|
vg_dest = run_pvs_command("noheadings vg_name device", destination)
|
||||||
|
if vg_src != vg_dest:
|
||||||
|
module.fail_json(
|
||||||
|
msg="Source and destination must be in the same VG. Source VG: '%s', Destination VG: '%s'." % (vg_src, vg_dest)
|
||||||
|
)
|
||||||
|
|
||||||
|
def get_allocated_pe(device):
|
||||||
|
try:
|
||||||
|
return int(run_pvs_command("noheadings pv_pe_alloc_count device", device))
|
||||||
|
except ValueError:
|
||||||
|
module.fail_json(msg="Invalid allocated PE count for device %s" % device)
|
||||||
|
|
||||||
|
allocated = get_allocated_pe(source)
|
||||||
|
if allocated == 0:
|
||||||
|
actions.append('no allocated extents to move')
|
||||||
|
else:
|
||||||
|
# Check destination has enough free space
|
||||||
|
def get_total_pe(device):
|
||||||
|
try:
|
||||||
|
return int(run_pvs_command("noheadings pv_pe_count device", device))
|
||||||
|
except ValueError:
|
||||||
|
module.fail_json(msg="Invalid total PE count for device %s" % device)
|
||||||
|
|
||||||
|
def get_free_pe(device):
|
||||||
|
return get_total_pe(device) - get_allocated_pe(device)
|
||||||
|
|
||||||
|
free_pe_dest = get_free_pe(destination)
|
||||||
|
if free_pe_dest < allocated:
|
||||||
|
module.fail_json(
|
||||||
|
msg="Destination device %s has only %d free physical extents, but source device %s has %d allocated extents. Not enough space." %
|
||||||
|
(destination, free_pe_dest, source, allocated)
|
||||||
|
)
|
||||||
|
|
||||||
|
if module.check_mode:
|
||||||
|
changed = True
|
||||||
|
actions.append('would move data from %s to %s' % (source, destination))
|
||||||
|
else:
|
||||||
|
pvmove_runner = CmdRunner(
|
||||||
|
module,
|
||||||
|
command="pvmove",
|
||||||
|
arg_formats=dict(
|
||||||
|
auto_answer=cmd_runner_fmt.as_bool("-y"),
|
||||||
|
atomic=cmd_runner_fmt.as_bool("--atomic"),
|
||||||
|
autobackup=cmd_runner_fmt.as_fixed("--autobackup", "y" if module.params['autobackup'] else "n"),
|
||||||
|
verbosity=cmd_runner_fmt.as_func(lambda v: ['-' + 'v' * v] if v > 0 else []),
|
||||||
|
source=cmd_runner_fmt.as_list(),
|
||||||
|
destination=cmd_runner_fmt.as_list(),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
verbosity = module._verbosity
|
||||||
|
with pvmove_runner("auto_answer atomic autobackup verbosity source destination") as ctx:
|
||||||
|
rc, out, err = ctx.run(
|
||||||
|
verbosity=verbosity,
|
||||||
|
source=source,
|
||||||
|
destination=destination
|
||||||
|
)
|
||||||
|
result['stdout'] = out
|
||||||
|
result['stderr'] = err
|
||||||
|
|
||||||
|
changed = True
|
||||||
|
actions.append('moved data from %s to %s' % (source, destination))
|
||||||
|
|
||||||
|
result['changed'] = changed
|
||||||
|
result['actions'] = actions
|
||||||
|
if actions:
|
||||||
|
result['msg'] = "PV data move: %s" % ", ".join(actions)
|
||||||
|
else:
|
||||||
|
result['msg'] = "No data to move from %s" % source
|
||||||
|
|
||||||
|
module.exit_json(**result)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
13
tests/integration/targets/lvm_pv_move_data/aliases
Normal file
13
tests/integration/targets/lvm_pv_move_data/aliases
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
# Copyright (c) Contributors to the Ansible project
|
||||||
|
# Based on the integraton test for the lvm_pv 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/lvm_pv_move_data/meta/main.yml
Normal file
9
tests/integration/targets/lvm_pv_move_data/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
|
39
tests/integration/targets/lvm_pv_move_data/tasks/cleanup.yml
Normal file
39
tests/integration/targets/lvm_pv_move_data/tasks/cleanup.yml
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
---
|
||||||
|
# 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: Unmounting temp file system
|
||||||
|
ansible.posix.mount:
|
||||||
|
fstab: '{{ remote_tmp_dir }}/fstab'
|
||||||
|
path: '{{ remote_tmp_dir }}/tmp_mount'
|
||||||
|
state: absent
|
||||||
|
|
||||||
|
- name: Removing xfs filesystem from LV lv_tmp_test
|
||||||
|
community.general.filesystem:
|
||||||
|
dev: /dev/vg_tmp_test/lv_tmp_test
|
||||||
|
state: absent
|
||||||
|
force: true
|
||||||
|
|
||||||
|
- name: Deleting testlv logical volume
|
||||||
|
community.general.lvol:
|
||||||
|
vg: testvg
|
||||||
|
lv: testlv
|
||||||
|
force: true
|
||||||
|
state: absent
|
||||||
|
|
||||||
|
- name: Detaching first loop device
|
||||||
|
ansible.builtin.command: losetup -d {{ loop_device_01.stdout }}
|
||||||
|
|
||||||
|
- name: Detaching second loop device
|
||||||
|
ansible.builtin.command: losetup -d {{ loop_device_02.stdout }}
|
||||||
|
|
||||||
|
- name: Removing first loop device file
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: "{{ remote_tmp_dir }}/test_lvm_pv_01.img"
|
||||||
|
state: absent
|
||||||
|
|
||||||
|
- name: Removing second loop device file
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: "{{ remote_tmp_dir }}/test_lvm_pv_02.img"
|
||||||
|
state: absent
|
115
tests/integration/targets/lvm_pv_move_data/tasks/creation.yml
Normal file
115
tests/integration/targets/lvm_pv_move_data/tasks/creation.yml
Normal file
|
@ -0,0 +1,115 @@
|
||||||
|
---
|
||||||
|
# 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: Creating a 500MB file for the first loop device
|
||||||
|
ansible.builtin.command: dd if=/dev/zero of={{ remote_tmp_dir }}/test_lvm_pv_01.img bs=1M count=500
|
||||||
|
args:
|
||||||
|
creates: "{{ remote_tmp_dir }}/test_lvm_pv_01.img"
|
||||||
|
|
||||||
|
- name: Creating a 1000MB file for the second loop device
|
||||||
|
ansible.builtin.command: dd if=/dev/zero of={{ remote_tmp_dir }}/test_lvm_pv_02.img bs=1M count=1000
|
||||||
|
args:
|
||||||
|
creates: "{{ remote_tmp_dir }}/test_lvm_pv_02.img"
|
||||||
|
|
||||||
|
- name: Pausing for a random time between 5-15 seconds
|
||||||
|
ansible.builtin.pause:
|
||||||
|
seconds: "{{ range(5, 16) | random }}"
|
||||||
|
|
||||||
|
- name: Creating loop device
|
||||||
|
ansible.builtin.command: losetup -f
|
||||||
|
register: loop_device_01
|
||||||
|
|
||||||
|
- name: Wiping existing LVM metadata
|
||||||
|
community.general.lvm_pv:
|
||||||
|
device: "{{ loop_device_01.stdout }}"
|
||||||
|
force: true
|
||||||
|
state: absent
|
||||||
|
|
||||||
|
- name: Associating loop device with file
|
||||||
|
ansible.builtin.command: 'losetup {{ loop_device_01.stdout }} {{ remote_tmp_dir }}/test_lvm_pv_01.img'
|
||||||
|
|
||||||
|
- name: Pausing for a random time between 5-15 seconds
|
||||||
|
ansible.builtin.pause:
|
||||||
|
seconds: "{{ range(5, 16) | random }}"
|
||||||
|
|
||||||
|
- name: Creating loop device
|
||||||
|
ansible.builtin.command: losetup -f
|
||||||
|
register: loop_device_02
|
||||||
|
|
||||||
|
- name: Wiping existing LVM metadata
|
||||||
|
community.general.lvm_pv:
|
||||||
|
device: "{{ loop_device_02.stdout }}"
|
||||||
|
force: true
|
||||||
|
state: absent
|
||||||
|
|
||||||
|
- name: Associating loop device with file
|
||||||
|
ansible.builtin.command: 'losetup {{ loop_device_02.stdout }} {{ remote_tmp_dir }}/test_lvm_pv_02.img'
|
||||||
|
|
||||||
|
- name: Creating physical volume for the first loop device
|
||||||
|
community.general.lvm_pv:
|
||||||
|
device: "{{ loop_device_01.stdout }}"
|
||||||
|
register: pv_creation_result_01
|
||||||
|
|
||||||
|
- name: Checking the first physical volume size
|
||||||
|
ansible.builtin.command: pvs --noheadings -o pv_size --units M {{ loop_device_01.stdout }}
|
||||||
|
register: pv_size_output_01
|
||||||
|
|
||||||
|
- name: Creating physical volume for the second loop device
|
||||||
|
community.general.lvm_pv:
|
||||||
|
device: "{{ loop_device_02.stdout }}"
|
||||||
|
register: pv_creation_result_02
|
||||||
|
|
||||||
|
- name: Checking the second physical volume size
|
||||||
|
ansible.builtin.command: pvs --noheadings -o pv_size --units M {{ loop_device_02.stdout }}
|
||||||
|
register: pv_size_output_02
|
||||||
|
|
||||||
|
- name: Creating volume group
|
||||||
|
community.general.lvg:
|
||||||
|
vg: testvg
|
||||||
|
pvs:
|
||||||
|
- "{{ loop_device_01.stdout }}"
|
||||||
|
- "{{ loop_device_02.stdout }}"
|
||||||
|
force: true
|
||||||
|
register: vg_creation_result
|
||||||
|
|
||||||
|
- name: Creating LV testlv on VG testvg
|
||||||
|
community.general.lvol:
|
||||||
|
vg: testvg
|
||||||
|
lv: testlv
|
||||||
|
size: 100%FREE
|
||||||
|
force: true
|
||||||
|
register: lv_creation_result
|
||||||
|
|
||||||
|
- name: Creating xfs filesystem on LV testlv
|
||||||
|
community.general.filesystem:
|
||||||
|
dev: /dev/testvg/testlv
|
||||||
|
fstype: xfs
|
||||||
|
state: present
|
||||||
|
register: fs_creation_result
|
||||||
|
|
||||||
|
- name: Mounting LV testlv
|
||||||
|
ansible.posix.mount:
|
||||||
|
fstab: '{{ remote_tmp_dir }}/fstab'
|
||||||
|
path: '{{ remote_tmp_dir }}/tmp_mount'
|
||||||
|
src: '/dev/testvg/testlv'
|
||||||
|
fstype: xfs
|
||||||
|
opts: rw,noauto
|
||||||
|
state: mounted
|
||||||
|
register: mount_result
|
||||||
|
|
||||||
|
- name: Asserting PVs, VG, LV and filesystem were created successfully
|
||||||
|
ansible.builtin.assert:
|
||||||
|
that:
|
||||||
|
- pv_creation_result_01 is changed
|
||||||
|
- pv_creation_result_02 is changed
|
||||||
|
- vg_creation_result is changed
|
||||||
|
- lv_creation_result is changed
|
||||||
|
- fs_creation_result is changed
|
||||||
|
- (pv_size_output_01.stdout | trim | regex_replace('M', '') | float) > 450
|
||||||
|
- (pv_size_output_01.stdout | trim | regex_replace('M', '') | float) < 600
|
||||||
|
- (pv_size_output_02.stdout | trim | regex_replace('M', '') | float) > 950
|
||||||
|
- (pv_size_output_02.stdout | trim | regex_replace('M', '') | float) < 1100
|
||||||
|
- "'created' in pv_creation_result_01.msg"
|
||||||
|
- "'created' in pv_creation_result_02.msg"
|
29
tests/integration/targets/lvm_pv_move_data/tasks/main.yml
Normal file
29
tests/integration/targets/lvm_pv_move_data/tasks/main.yml
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
---
|
||||||
|
####################################################################
|
||||||
|
# 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 integration test for the lvm_pv 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
|
||||||
|
- xfsprogs
|
||||||
|
state: present
|
||||||
|
|
||||||
|
- name: Testing lvm_pv_move_data module
|
||||||
|
block:
|
||||||
|
- import_tasks: prepare.yml
|
||||||
|
|
||||||
|
- import_tasks: creation.yml
|
||||||
|
|
||||||
|
- import_tasks: moving.yml
|
||||||
|
|
||||||
|
always:
|
||||||
|
- import_tasks: cleanup.yml
|
36
tests/integration/targets/lvm_pv_move_data/tasks/moving.yml
Normal file
36
tests/integration/targets/lvm_pv_move_data/tasks/moving.yml
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
---
|
||||||
|
# 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: Creating a 50MB file on the mounted LV
|
||||||
|
ansible.builtin.command: dd if=/dev/zero of={{ remote_tmp_dir }}/tmp_mount/test_file bs=1M count=50
|
||||||
|
args:
|
||||||
|
creates: "{{ remote_tmp_dir }}/tmp_mount/test_file"
|
||||||
|
|
||||||
|
- name: Growing the second loop device file to 1500MB
|
||||||
|
ansible.builtin.shell: truncate -s 1500M {{ remote_tmp_dir }}/test_lvm_pv_02.img
|
||||||
|
|
||||||
|
- name: Refreshing the second loop device
|
||||||
|
ansible.builtin.shell: losetup -c {{ loop_device_02.stdout }}
|
||||||
|
|
||||||
|
- name: Resizing the second physical volume
|
||||||
|
community.general.lvm_pv:
|
||||||
|
device: "{{ loop_device_02.stdout }}"
|
||||||
|
resize: true
|
||||||
|
|
||||||
|
- name: Moving data from between PVs (both in same VG)
|
||||||
|
community.general.lvm_pv_move_data:
|
||||||
|
source: "{{ loop_device_01.stdout }}"
|
||||||
|
destination: "{{ loop_device_02.stdout }}"
|
||||||
|
register: move_result
|
||||||
|
|
||||||
|
- name: Debugging move result
|
||||||
|
ansible.builtin.debug:
|
||||||
|
var: move_result
|
||||||
|
|
||||||
|
- name: Asserting data was moved successfully
|
||||||
|
ansible.builtin.assert:
|
||||||
|
that:
|
||||||
|
- move_result is changed
|
||||||
|
- "'moved data from' in move_result.msg"
|
23
tests/integration/targets/lvm_pv_move_data/tasks/prepare.yml
Normal file
23
tests/integration/targets/lvm_pv_move_data/tasks/prepare.yml
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
---
|
||||||
|
# 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: Removing xfs filesystem from LV lv_tmp_test
|
||||||
|
community.general.filesystem:
|
||||||
|
dev: /dev/vg_tmp_test/lv_tmp_test
|
||||||
|
state: absent
|
||||||
|
force: true
|
||||||
|
|
||||||
|
- name: Deleting testlv logical volume
|
||||||
|
community.general.lvol:
|
||||||
|
vg: testvg
|
||||||
|
lv: testlv
|
||||||
|
force: true
|
||||||
|
state: absent
|
||||||
|
|
||||||
|
- name: Deleting volume group testvg
|
||||||
|
community.general.lvg:
|
||||||
|
vg: testvg
|
||||||
|
force: true
|
||||||
|
state: absent
|
Loading…
Add table
Add a link
Reference in a new issue