mirror of
https://github.com/ansible-collections/community.general.git
synced 2025-07-28 15:41:22 -07:00
New module zpool (#10146)
* Add zpool module * Add botmeta * Use str.format instead of f-strings * Remove nonlocal usage * Add check to only pass ashift to zpool add * Extend ansible_spec and remove unnecessary validation * Apply suggestions and fix style * Fix indentation of yaml lists * Add method to normalize vdevs Fix role: none in vdevs * Use CmdRunner instead of run_command * Fix styling and documentation * Use str.format instead of f-strings * Make sure vdevs are only required when state is present * Add support for loop devices and normalize vdev type * Add integration tests * Add missing test dependencies for alpine and redhat * Skip integration tests on rhel10 until there there packages available * Use package module for better auto detection of package manager on rhel * Add copyright header * Skip tests on rhel and remove redhat install requirements * Ensure loop devices under /dev exist * Enable usage of files as pool devices * Remove disk setup * Use files as disks * Apply suggestions * Fix argument_spec
This commit is contained in:
parent
8bd68e7e41
commit
928622703d
11 changed files with 1064 additions and 0 deletions
14
tests/integration/targets/zpool/aliases
Normal file
14
tests/integration/targets/zpool/aliases
Normal file
|
@ -0,0 +1,14 @@
|
|||
# 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
|
||||
|
||||
azp/posix/3
|
||||
azp/posix/vm
|
||||
destructive
|
||||
needs/privileged
|
||||
skip/aix
|
||||
skip/freebsd
|
||||
skip/osx
|
||||
skip/macos
|
||||
skip/rhel
|
||||
skip/docker
|
34
tests/integration/targets/zpool/defaults/main.yml
Normal file
34
tests/integration/targets/zpool/defaults/main.yml
Normal file
|
@ -0,0 +1,34 @@
|
|||
---
|
||||
# Copyright (c) 2025, Tom Hesse <contact@tomhesse.xyz>
|
||||
# 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
|
||||
|
||||
zpool_single_disk_config:
|
||||
- "{{ remote_tmp_dir }}/disk0.img"
|
||||
|
||||
zpool_mirror_disk_config:
|
||||
- "{{ remote_tmp_dir }}/disk1.img"
|
||||
- "{{ remote_tmp_dir }}/disk2.img"
|
||||
|
||||
zpool_raidz_disk_config:
|
||||
- "{{ remote_tmp_dir }}/disk3.img"
|
||||
- "{{ remote_tmp_dir }}/disk4.img"
|
||||
|
||||
zpool_vdevs_disk_config:
|
||||
vdev1:
|
||||
- "{{ remote_tmp_dir }}/disk5.img"
|
||||
vdev2:
|
||||
- "{{ remote_tmp_dir }}/disk6.img"
|
||||
vdev3:
|
||||
- "{{ remote_tmp_dir }}/disk7.img"
|
||||
- "{{ remote_tmp_dir }}/disk8.img"
|
||||
vdev4:
|
||||
- "{{ remote_tmp_dir }}/disk9.img"
|
||||
- "{{ remote_tmp_dir }}/disk10.img"
|
||||
|
||||
zpool_disk_configs: "{{ zpool_single_disk_config + zpool_mirror_disk_config + zpool_raidz_disk_config + (zpool_vdevs_disk_config.values() | flatten) }}"
|
||||
|
||||
zpool_single_disk_pool_name: spool
|
||||
zpool_mirror_disk_pool_name: mpool
|
||||
zpool_raidz_disk_pool_name: rpool
|
||||
zpool_generic_pool_name: tank
|
7
tests/integration/targets/zpool/meta/main.yml
Normal file
7
tests/integration/targets/zpool/meta/main.yml
Normal file
|
@ -0,0 +1,7 @@
|
|||
---
|
||||
# Copyright (c) 2025, Tom Hesse <contact@tomhesse.xyz>
|
||||
# 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_remote_tmp_dir
|
147
tests/integration/targets/zpool/tasks/add_remove_vdevs.yml
Normal file
147
tests/integration/targets/zpool/tasks/add_remove_vdevs.yml
Normal file
|
@ -0,0 +1,147 @@
|
|||
---
|
||||
# Copyright (c) 2025, Tom Hesse <contact@tomhesse.xyz>
|
||||
# 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: Test adding a single disk vdev
|
||||
block:
|
||||
- name: Ensure a single disk pool exists
|
||||
community.general.zpool:
|
||||
name: "{{ zpool_generic_pool_name }}"
|
||||
vdevs:
|
||||
- disks: "{{ zpool_vdevs_disk_config.vdev1 }}"
|
||||
state: present
|
||||
|
||||
- name: Add a single disk vdev
|
||||
community.general.zpool:
|
||||
name: "{{ zpool_generic_pool_name }}"
|
||||
vdevs:
|
||||
- disks: "{{ zpool_vdevs_disk_config.vdev1 }}"
|
||||
- disks: "{{ zpool_vdevs_disk_config.vdev2 }}"
|
||||
state: present
|
||||
|
||||
- name: Check if vdev was added
|
||||
ansible.builtin.command:
|
||||
cmd: "zpool status -P -L {{ zpool_generic_pool_name }}"
|
||||
register: single_disk_pool_check
|
||||
changed_when: false
|
||||
|
||||
- name: Assert that added disk is present
|
||||
ansible.builtin.assert:
|
||||
that:
|
||||
- "zpool_vdevs_disk_config.vdev2[0] in single_disk_pool_check.stdout"
|
||||
|
||||
- name: Ensure the single disk pool is absent
|
||||
community.general.zpool:
|
||||
name: "{{ zpool_generic_pool_name }}"
|
||||
state: absent
|
||||
|
||||
- name: Test adding a mirror vdev
|
||||
block:
|
||||
- name: Ensure a single disk pool exists
|
||||
community.general.zpool:
|
||||
name: "{{ zpool_generic_pool_name }}"
|
||||
vdevs:
|
||||
- disks: "{{ zpool_vdevs_disk_config.vdev1 }}"
|
||||
state: present
|
||||
|
||||
- name: Add a mirror vdev
|
||||
community.general.zpool:
|
||||
name: "{{ zpool_generic_pool_name }}"
|
||||
force: true # This is necessary because of the mismatched replication level
|
||||
vdevs:
|
||||
- disks: "{{ zpool_vdevs_disk_config.vdev1 }}"
|
||||
- type: mirror
|
||||
disks: "{{ zpool_vdevs_disk_config.vdev3 }}"
|
||||
state: present
|
||||
|
||||
- name: Check if vdev was added
|
||||
ansible.builtin.command:
|
||||
cmd: "zpool status -P -L {{ zpool_generic_pool_name }}"
|
||||
register: mirror_pool_check
|
||||
changed_when: false
|
||||
|
||||
- name: Assert that added vdev is present
|
||||
ansible.builtin.assert:
|
||||
that:
|
||||
- "zpool_vdevs_disk_config.vdev3[0] in mirror_pool_check.stdout"
|
||||
- "zpool_vdevs_disk_config.vdev3[1] in mirror_pool_check.stdout"
|
||||
|
||||
- name: Ensure the single disk pool is absent
|
||||
community.general.zpool:
|
||||
name: "{{ zpool_generic_pool_name }}"
|
||||
state: absent
|
||||
|
||||
- name: Test adding a raidz vdev
|
||||
block:
|
||||
- name: Ensure a single disk pool exists
|
||||
community.general.zpool:
|
||||
name: "{{ zpool_generic_pool_name }}"
|
||||
vdevs:
|
||||
- disks: "{{ zpool_vdevs_disk_config.vdev1 }}"
|
||||
state: present
|
||||
|
||||
- name: Add a raidz vdev
|
||||
community.general.zpool:
|
||||
name: "{{ zpool_generic_pool_name }}"
|
||||
force: true # This is necessary because of the mismatched replication level
|
||||
vdevs:
|
||||
- disks: "{{ zpool_vdevs_disk_config.vdev1 }}"
|
||||
- type: raidz
|
||||
disks: "{{ zpool_vdevs_disk_config.vdev3 }}"
|
||||
state: present
|
||||
|
||||
- name: Check if vdev was added
|
||||
ansible.builtin.command:
|
||||
cmd: "zpool status -P -L {{ zpool_generic_pool_name }}"
|
||||
register: raidz_pool_check
|
||||
changed_when: false
|
||||
|
||||
- name: Assert that added vdev is present
|
||||
ansible.builtin.assert:
|
||||
that:
|
||||
- "zpool_vdevs_disk_config.vdev3[0] in raidz_pool_check.stdout"
|
||||
- "zpool_vdevs_disk_config.vdev3[1] in raidz_pool_check.stdout"
|
||||
|
||||
- name: Ensure the single disk pool is absent
|
||||
community.general.zpool:
|
||||
name: "{{ zpool_generic_pool_name }}"
|
||||
state: absent
|
||||
|
||||
- name: Test removing an existing vdev
|
||||
block:
|
||||
- name: Ensure a pool with two mirrored vdevs exists
|
||||
community.general.zpool:
|
||||
name: "{{ zpool_generic_pool_name }}"
|
||||
vdevs:
|
||||
- type: mirror
|
||||
disks: "{{ zpool_vdevs_disk_config.vdev3 }}"
|
||||
- type: mirror
|
||||
disks: "{{ zpool_vdevs_disk_config.vdev4 }}"
|
||||
state: present
|
||||
|
||||
- name: Remove a vdev
|
||||
community.general.zpool:
|
||||
name: "{{ zpool_generic_pool_name }}"
|
||||
vdevs:
|
||||
- type: mirror
|
||||
disks: "{{ zpool_vdevs_disk_config.vdev4 }}"
|
||||
state: present
|
||||
|
||||
- name: Check if vdev was removed
|
||||
ansible.builtin.command:
|
||||
cmd: "zpool status -P -L {{ zpool_generic_pool_name }}"
|
||||
register: remove_vdev_check
|
||||
changed_when: false
|
||||
|
||||
- name: Assert that removed vdev is absent
|
||||
ansible.builtin.assert:
|
||||
that:
|
||||
- "zpool_vdevs_disk_config.vdev3[0] not in remove_vdev_check.stdout"
|
||||
- "zpool_vdevs_disk_config.vdev3[1] not in remove_vdev_check.stdout"
|
||||
- "'Removal of vdev' in remove_vdev_check.stdout"
|
||||
|
||||
- name: Ensure the pool is absent
|
||||
community.general.zpool:
|
||||
name: "{{ zpool_generic_pool_name }}"
|
||||
state: absent
|
123
tests/integration/targets/zpool/tasks/create_destroy.yml
Normal file
123
tests/integration/targets/zpool/tasks/create_destroy.yml
Normal file
|
@ -0,0 +1,123 @@
|
|||
---
|
||||
# Copyright (c) 2025, Tom Hesse <contact@tomhesse.xyz>
|
||||
# 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: Test single disk pool creation
|
||||
block:
|
||||
- name: Ensure single disk pool exists
|
||||
community.general.zpool:
|
||||
name: "{{ zpool_single_disk_pool_name }}"
|
||||
vdevs:
|
||||
- disks: "{{ zpool_single_disk_config }}"
|
||||
|
||||
- name: Check if single disk pool exists
|
||||
ansible.builtin.command:
|
||||
cmd: "zpool list -H -o name,health {{ zpool_single_disk_pool_name }}"
|
||||
register: single_disk_pool_check
|
||||
changed_when: false
|
||||
|
||||
- name: Assert that single disk pool is online
|
||||
ansible.builtin.assert:
|
||||
that:
|
||||
- "zpool_single_disk_pool_name in single_disk_pool_check.stdout"
|
||||
- "'ONLINE' in single_disk_pool_check.stdout"
|
||||
|
||||
- name: Test mirror disk pool creation
|
||||
block:
|
||||
- name: Ensure mirror disk pool exists
|
||||
community.general.zpool:
|
||||
name: "{{ zpool_mirror_disk_pool_name }}"
|
||||
vdevs:
|
||||
- type: mirror
|
||||
disks: "{{ zpool_mirror_disk_config }}"
|
||||
|
||||
- name: Check if mirror disk pool exists
|
||||
ansible.builtin.command:
|
||||
cmd: "zpool list -H -o name,health {{ zpool_mirror_disk_pool_name }}"
|
||||
register: mirror_disk_pool_check
|
||||
changed_when: false
|
||||
|
||||
- name: Assert that mirror disk pool is online
|
||||
ansible.builtin.assert:
|
||||
that:
|
||||
- "zpool_mirror_disk_pool_name in mirror_disk_pool_check.stdout"
|
||||
- "'ONLINE' in mirror_disk_pool_check.stdout"
|
||||
|
||||
- name: Test raidz disk pool creation
|
||||
block:
|
||||
- name: Ensure raidz disk pool exists
|
||||
community.general.zpool:
|
||||
name: "{{ zpool_raidz_disk_pool_name }}"
|
||||
vdevs:
|
||||
- type: raidz
|
||||
disks: "{{ zpool_raidz_disk_config }}"
|
||||
|
||||
- name: Check if raidz disk pool exists
|
||||
ansible.builtin.command:
|
||||
cmd: "zpool list -H -o name,health {{ zpool_raidz_disk_pool_name }}"
|
||||
register: raidz_disk_pool_check
|
||||
changed_when: false
|
||||
|
||||
- name: Assert that raidz disk pool is online
|
||||
ansible.builtin.assert:
|
||||
that:
|
||||
- "zpool_raidz_disk_pool_name in raidz_disk_pool_check.stdout"
|
||||
- "'ONLINE' in raidz_disk_pool_check.stdout"
|
||||
|
||||
- name: Test single disk pool deletion
|
||||
block:
|
||||
- name: Ensure single disk pool is absent
|
||||
community.general.zpool:
|
||||
name: "{{ zpool_single_disk_pool_name }}"
|
||||
state: absent
|
||||
|
||||
- name: Check if single disk pool is absent
|
||||
ansible.builtin.command:
|
||||
cmd: "zpool list -H -o name,health {{ zpool_single_disk_pool_name }}"
|
||||
register: single_disk_pool_check
|
||||
ignore_errors: true
|
||||
changed_when: false
|
||||
|
||||
- name: Assert that single disk pool is online
|
||||
ansible.builtin.assert:
|
||||
that:
|
||||
- "'no such pool' in single_disk_pool_check.stderr"
|
||||
|
||||
- name: Test mirror disk pool deletion
|
||||
block:
|
||||
- name: Ensure mirror disk pool is absent
|
||||
community.general.zpool:
|
||||
name: "{{ zpool_mirror_disk_pool_name }}"
|
||||
state: absent
|
||||
|
||||
- name: Check if mirror disk pool is absent
|
||||
ansible.builtin.command:
|
||||
cmd: "zpool list -H -o name,health {{ zpool_mirror_disk_pool_name }}"
|
||||
register: mirror_disk_pool_check
|
||||
ignore_errors: true
|
||||
changed_when: false
|
||||
|
||||
- name: Assert that mirror disk pool is online
|
||||
ansible.builtin.assert:
|
||||
that:
|
||||
- "'no such pool' in mirror_disk_pool_check.stderr"
|
||||
|
||||
- name: Test raidz disk pool deletion
|
||||
block:
|
||||
- name: Ensure raidz disk pool is absent
|
||||
community.general.zpool:
|
||||
name: "{{ zpool_raidz_disk_pool_name }}"
|
||||
state: absent
|
||||
|
||||
- name: Check if raidz disk pool is absent
|
||||
ansible.builtin.command:
|
||||
cmd: "zpool list -H -o name,health {{ zpool_raidz_disk_pool_name }}"
|
||||
register: raidz_disk_pool_check
|
||||
ignore_errors: true
|
||||
changed_when: false
|
||||
|
||||
- name: Assert that raidz disk pool is online
|
||||
ansible.builtin.assert:
|
||||
that:
|
||||
- "'no such pool' in raidz_disk_pool_check.stderr"
|
|
@ -0,0 +1,15 @@
|
|||
---
|
||||
# Copyright (c) 2025, Tom Hesse <contact@tomhesse.xyz>
|
||||
# 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
|
||||
community.general.apk:
|
||||
name:
|
||||
- zfs
|
||||
- zfs-lts
|
||||
|
||||
- name: Load zfs module
|
||||
community.general.modprobe:
|
||||
name: zfs
|
||||
state: present
|
|
@ -0,0 +1,10 @@
|
|||
---
|
||||
# Copyright (c) 2025, Tom Hesse <contact@tomhesse.xyz>
|
||||
# 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
|
||||
ansible.builtin.apt:
|
||||
name:
|
||||
- zfsutils-linux
|
||||
- util-linux
|
25
tests/integration/targets/zpool/tasks/main.yml
Normal file
25
tests/integration/targets/zpool/tasks/main.yml
Normal file
|
@ -0,0 +1,25 @@
|
|||
---
|
||||
# Copyright (c) 2025, Tom Hesse <contact@tomhesse.xyz>
|
||||
# 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: Execute integration tests
|
||||
become: true
|
||||
block:
|
||||
- name: Ensure disk files exists
|
||||
ansible.builtin.command:
|
||||
cmd: "dd if=/dev/zero of={{ item }} bs=1M count=256 conv=fsync"
|
||||
creates: "{{ item }}"
|
||||
loop: "{{ zpool_disk_configs }}"
|
||||
|
||||
- name: Include distribution specific install_requirements.yml
|
||||
ansible.builtin.include_tasks: install_requirements_{{ ansible_distribution | lower }}.yml
|
||||
|
||||
- name: Include create_destroy.yml
|
||||
ansible.builtin.include_tasks: create_destroy.yml
|
||||
|
||||
- name: Include add_remove_vdevs.yml
|
||||
ansible.builtin.include_tasks: add_remove_vdevs.yml
|
||||
|
||||
- name: Include properties.yml
|
||||
ansible.builtin.include_tasks: properties.yml
|
73
tests/integration/targets/zpool/tasks/properties.yml
Normal file
73
tests/integration/targets/zpool/tasks/properties.yml
Normal file
|
@ -0,0 +1,73 @@
|
|||
---
|
||||
# Copyright (c) 2025, Tom Hesse <contact@tomhesse.xyz>
|
||||
# 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: Ensure pool with two mirrored disks exists
|
||||
community.general.zpool:
|
||||
name: "{{ zpool_generic_pool_name }}"
|
||||
pool_properties:
|
||||
ashift: 12
|
||||
filesystem_properties:
|
||||
compression: off
|
||||
vdevs:
|
||||
- type: mirror
|
||||
disks: "{{ zpool_vdevs_disk_config.vdev3 }}"
|
||||
- type: mirror
|
||||
disks: "{{ zpool_vdevs_disk_config.vdev4 }}"
|
||||
state: present
|
||||
|
||||
- name: Test changing of a pool property
|
||||
block:
|
||||
- name: Change ashift from 12 to 13
|
||||
community.general.zpool:
|
||||
name: "{{ zpool_generic_pool_name }}"
|
||||
pool_properties:
|
||||
ashift: 13
|
||||
vdevs:
|
||||
- type: mirror
|
||||
disks: "{{ zpool_vdevs_disk_config.vdev3 }}"
|
||||
- type: mirror
|
||||
disks: "{{ zpool_vdevs_disk_config.vdev4 }}"
|
||||
state: present
|
||||
|
||||
- name: Check ashift
|
||||
ansible.builtin.command:
|
||||
cmd: "zpool get -H -o value ashift {{ zpool_generic_pool_name }}"
|
||||
changed_when: false
|
||||
register: ashift_check
|
||||
|
||||
- name: Assert ashift has changed
|
||||
ansible.builtin.assert:
|
||||
that:
|
||||
- "'13' in ashift_check.stdout"
|
||||
|
||||
- name: Test changing of a dataset property
|
||||
block:
|
||||
- name: Change compression from off to lz4
|
||||
community.general.zpool:
|
||||
name: "{{ zpool_generic_pool_name }}"
|
||||
filesystem_properties:
|
||||
compression: lz4
|
||||
vdevs:
|
||||
- type: mirror
|
||||
disks: "{{ zpool_vdevs_disk_config.vdev3 }}"
|
||||
- type: mirror
|
||||
disks: "{{ zpool_vdevs_disk_config.vdev4 }}"
|
||||
state: present
|
||||
|
||||
- name: Check compression
|
||||
ansible.builtin.command:
|
||||
cmd: "zfs get -H -o value compression {{ zpool_generic_pool_name }}"
|
||||
changed_when: false
|
||||
register: compression_check
|
||||
|
||||
- name: Assert compression has changed
|
||||
ansible.builtin.assert:
|
||||
that:
|
||||
- "'lz4' in compression_check.stdout"
|
||||
|
||||
- name: Cleanup pool
|
||||
community.general.zpool:
|
||||
name: "{{ zpool_generic_pool_name }}"
|
||||
state: absent
|
Loading…
Add table
Add a link
Reference in a new issue