initial project commit
This commit is contained in:
@ -0,0 +1,39 @@
|
||||
# Testing the LVM Snapshot Role
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- All the tests are in the form of ansible playbooks.
|
||||
- All playbooks expect that the target machine will have a secondary storage device to be used for testing.
|
||||
|
||||
## Variables
|
||||
The variables may be passed as part of the inventory or using a separate file.
|
||||
|
||||
```yaml
|
||||
device: < device node without `/dev`. e.g. vdb >
|
||||
```
|
||||
|
||||
## Ansible Configuration
|
||||
|
||||
In order to run the tests from the repo without having to install them,
|
||||
the tests directory includes an [ansible.cfg](./ansible.cfg) file.
|
||||
Make sure to point to it when running the test playbook
|
||||
|
||||
## Running a test
|
||||
|
||||
### Inventory file
|
||||
|
||||
In this example, the `device` parameter is passed in the `inventory.yml` file
|
||||
```yaml
|
||||
all:
|
||||
hosts:
|
||||
<FQDN of test machine>:
|
||||
device: vdb
|
||||
```
|
||||
|
||||
### Command line
|
||||
|
||||
Running the [snapshot revert playbook](./test-revert-playbook.yml) test from the repo
|
||||
|
||||
```bash
|
||||
ANSIBLE_CONFIG=./tests/ansible.cfg ansible-playbook -K -i inventory.yml tests/test-revert-playbook.yml
|
||||
```
|
@ -0,0 +1,2 @@
|
||||
[defaults]
|
||||
roles_path=~/.ansible/roles:/usr/share/ansible/roles:/etc/ansible/roles:../roles
|
@ -0,0 +1,15 @@
|
||||
- name: Generate snapshot list out of volumes list
|
||||
ansible.builtin.set_fact:
|
||||
_snapshots: "{{ (_snapshots | default([])) + [{'vg': volume_group, 'lv': item.name, 'size': item.size}] }}"
|
||||
loop: "{{ volumes }}"
|
||||
|
||||
- name: Create the snapshot
|
||||
vars:
|
||||
snapshot_create_volumes: "{{ _snapshots }}"
|
||||
snapshot_create_set_name: "{{ snapshot_set_name }}"
|
||||
ansible.builtin.include_role:
|
||||
name: snapshot_create
|
||||
|
||||
- name: Verify that the snapshot was created
|
||||
ansible.builtin.include_tasks: verify-snapshot-created.yml
|
||||
loop: "{{ volumes }}"
|
@ -0,0 +1,40 @@
|
||||
- name: Fill the volume
|
||||
block:
|
||||
- name: Set the retry count
|
||||
ansible.builtin.set_fact:
|
||||
_retry_count: "{{ (_retry_count | default('-1') | int) + 1 }}"
|
||||
|
||||
- name: Generate the Sub-Directory name
|
||||
ansible.builtin.set_fact:
|
||||
_sub_dir_name: "{{ lookup('community.general.random_string', upper=false, numbers=false, special=false) }}"
|
||||
|
||||
- name: Make a copy of the boot partition
|
||||
ansible.builtin.copy:
|
||||
src: /boot
|
||||
dest: "{{ test_directory }}/{{ _sub_dir_name }}"
|
||||
remote_src: true
|
||||
mode: '0777'
|
||||
|
||||
- name: Get the status of the snapshot
|
||||
ansible.builtin.command: "lvs --select 'lv_name = {{ volume_name }}_{{ snapshot_set_name }}' --reportformat json"
|
||||
register: _lv_status_check
|
||||
changed_when: false
|
||||
|
||||
- name: Store the snapshot data_percent
|
||||
ansible.builtin.set_fact:
|
||||
_snapshot_data_percent: "{{ ((_lv_status_check.stdout | from_json).report[0].lv[0].data_percent) }}"
|
||||
|
||||
- name: Check if snapshot is full enough
|
||||
ansible.builtin.assert:
|
||||
that: _snapshot_data_percent|float > snapshot_fill_percent|float
|
||||
quiet: true
|
||||
|
||||
rescue:
|
||||
- name: Check the retry count to avoid endless loop
|
||||
ansible.builtin.assert:
|
||||
that: (_retry_count|int) < (snapshot_max_retry|int)
|
||||
fail_msg: "Ended after {{ snapshot_max_retry }} retries"
|
||||
success_msg: "Volume is not full enough ({{ _snapshot_data_percent }}) - Run again..."
|
||||
|
||||
- name: Include the same tasks file again
|
||||
ansible.builtin.include_tasks: fill-snapshot.yml
|
@ -0,0 +1,11 @@
|
||||
- name: Unmount the "{{ item.directory }}"
|
||||
ansible.posix.mount:
|
||||
path: "{{ item.directory }}"
|
||||
state: absent
|
||||
|
||||
- name: Remove the logical volume
|
||||
community.general.lvol:
|
||||
vg: "{{ volume_group }}"
|
||||
lv: "{{ item.name }}"
|
||||
force: true
|
||||
state: absent
|
@ -0,0 +1,25 @@
|
||||
- name: Cleanup the volumes
|
||||
ansible.builtin.include_tasks: post-test-clean-volume.yml
|
||||
loop: "{{ volumes }}"
|
||||
|
||||
- name: Remove the volume group
|
||||
community.general.lvg:
|
||||
vg: "{{ volume_group }}"
|
||||
pvs: "/dev/{{ device }}1"
|
||||
state: absent
|
||||
|
||||
- name: Remove the PV
|
||||
ansible.builtin.command: "pvremove /dev/{{ device }}1"
|
||||
changed_when: true
|
||||
|
||||
- name: Cleanup the system.devices file
|
||||
ansible.builtin.lineinfile:
|
||||
path: /etc/lvm/devices/system.devices
|
||||
regexp: "IDTYPE=devname IDNAME=/dev/{{ device }}1 DEVNAME=/dev/{{ device }}1 PVID=. PART=1"
|
||||
state: absent
|
||||
|
||||
- name: Delete the partition
|
||||
community.general.parted:
|
||||
device: "/dev/{{ device }}"
|
||||
number: 1
|
||||
state: absent
|
@ -0,0 +1,18 @@
|
||||
- name: Create the logical volume
|
||||
community.general.lvol:
|
||||
vg: "{{ volume_group }}"
|
||||
lv: "{{ item.name }}"
|
||||
size: "{{ item.size }}"
|
||||
force: true
|
||||
|
||||
- name: Format the ext4 filesystem
|
||||
community.general.filesystem:
|
||||
fstype: ext4
|
||||
dev: "/dev/{{ volume_group }}/{{ item.name }}"
|
||||
|
||||
- name: Mount the lv on "{{ item.directory }}"
|
||||
ansible.posix.mount:
|
||||
path: "{{ item.directory }}"
|
||||
src: "/dev/{{ volume_group }}/{{ item.name }}"
|
||||
fstype: ext4
|
||||
state: mounted
|
@ -0,0 +1,23 @@
|
||||
- name: Create partition
|
||||
community.general.parted:
|
||||
device: "/dev/{{ device }}"
|
||||
number: 1
|
||||
part_end: 9GiB
|
||||
flags:
|
||||
- lvm
|
||||
state: present
|
||||
|
||||
- name: Install lvm2 dependency
|
||||
ansible.builtin.package:
|
||||
name: lvm2
|
||||
state: present
|
||||
|
||||
- name: Create the volume group
|
||||
community.general.lvg:
|
||||
vg: "{{ volume_group }}"
|
||||
pvs: "/dev/{{ device }}1"
|
||||
pesize: 16
|
||||
|
||||
- name: Create and prepare the volumes
|
||||
ansible.builtin.include_tasks: pre-test-prepare-volume.yml
|
||||
loop: "{{ volumes }}"
|
@ -0,0 +1,62 @@
|
||||
- name: Test creating snapshots as percentage of free
|
||||
hosts: all
|
||||
become: true
|
||||
vars:
|
||||
volume_group: test_vg
|
||||
base_volume_name: test_lv
|
||||
volume_size: 3g
|
||||
base_test_directory: "/mnt/test"
|
||||
snapshot_set_name: demo_snap
|
||||
tasks:
|
||||
- name: Run pre-test steps
|
||||
vars:
|
||||
volumes:
|
||||
- name: "{{ base_volume_name }}-1"
|
||||
size: "{{ volume_size }}"
|
||||
directory: "{{ base_test_directory }}-1"
|
||||
- name: "{{ base_volume_name }}-2"
|
||||
size: "{{ volume_size }}"
|
||||
directory: "{{ base_test_directory }}-2"
|
||||
ansible.builtin.include_tasks: pre-test-tasks.yml
|
||||
|
||||
- name: Create the snapshot
|
||||
vars:
|
||||
volumes:
|
||||
- name: "{{ base_volume_name }}-1"
|
||||
size: 45%FREE
|
||||
- name: "{{ base_volume_name }}-2"
|
||||
size: 45%FREE
|
||||
ansible.builtin.include_tasks: create-snapshot.yml
|
||||
|
||||
- name: Verify the snapshot sizes and cleanup
|
||||
block:
|
||||
- name: Get the size of the created snapshot
|
||||
ansible.builtin.command: lvs --select 'vg_name = {{ volume_group }} && origin = {{ item }}' --units b --reportformat json
|
||||
register: lvs_response
|
||||
changed_when: false
|
||||
loop:
|
||||
- "{{ base_volume_name }}-1"
|
||||
- "{{ base_volume_name }}-2"
|
||||
- name: Parse report
|
||||
ansible.builtin.set_fact:
|
||||
lvs_sizes: "{{ (lvs_sizes | default([])) + [(item.stdout | from_json).report[0].lv[0].lv_size] }}"
|
||||
loop: "{{ lvs_response.results }}"
|
||||
- name: Assert that both snapshots have the same size
|
||||
ansible.builtin.assert:
|
||||
that: lvs_sizes[0] == lvs_sizes[1]
|
||||
fail_msg: "The snapshots were not created with the same size: {{ lvs_sizes[0] }} != {{ lvs_sizes[1] }}"
|
||||
success_msg: "Both snapshots were created with the same size: {{ lvs_sizes[0] }}"
|
||||
always:
|
||||
- name: Remove Snapshot
|
||||
vars:
|
||||
snapshot_remove_set_name: "{{ snapshot_set_name }}"
|
||||
ansible.builtin.include_role:
|
||||
name: snapshot_remove
|
||||
- name: Cleanup
|
||||
vars:
|
||||
volumes:
|
||||
- name: "{{ base_volume_name }}-1"
|
||||
directory: "{{ base_test_directory }}-1"
|
||||
- name: "{{ base_volume_name }}-2"
|
||||
directory: "{{ base_test_directory }}-2"
|
||||
ansible.builtin.include_tasks: post-test-tasks.yml
|
@ -0,0 +1,52 @@
|
||||
- name: Test revering to the snapshots
|
||||
hosts: all
|
||||
become: true
|
||||
vars:
|
||||
volume_group: test_vg
|
||||
test_directory: "/mnt/test"
|
||||
volume_name: test_lv
|
||||
volumes:
|
||||
- name: "{{ volume_name }}"
|
||||
size: 4g
|
||||
directory: "{{ test_directory }}"
|
||||
snapshot_set_name: demo_snap
|
||||
snapshot_fill_percent: 60
|
||||
snapshot_max_retry: 100
|
||||
tasks:
|
||||
- name: Run pre-test steps
|
||||
ansible.builtin.include_tasks: pre-test-tasks.yml
|
||||
|
||||
- name: Create the snapshot
|
||||
ansible.builtin.include_tasks: create-snapshot.yml
|
||||
|
||||
- name: Fill the snapshot
|
||||
ansible.builtin.include_tasks: fill-snapshot.yml
|
||||
|
||||
- name: Revert to Snapshot
|
||||
vars:
|
||||
snapshot_revert_set_name: "{{ snapshot_set_name }}"
|
||||
ansible.builtin.include_role:
|
||||
name: snapshot_revert
|
||||
|
||||
- name: Verify that the snapshot was completely drained
|
||||
block:
|
||||
- name: Verify that the snapshot no longer exists
|
||||
vars:
|
||||
volume_name: test_lv
|
||||
ansible.builtin.include_tasks: verify-snapshot-not-exist.yml
|
||||
- name: Verify that the snapshot was drained before returning
|
||||
block:
|
||||
- name: Get the status of the volume
|
||||
ansible.builtin.command: "lvs --select 'lv_name = {{ volume_name }}' --reportformat json"
|
||||
register: _lv_status_check
|
||||
changed_when: false
|
||||
- name: Store the snapshot data_percent
|
||||
ansible.builtin.set_fact:
|
||||
volume_data_percent: "{{ ((_lv_status_check.stdout | from_json).report[0].lv[0].data_percent) }}"
|
||||
- name: Assert volume_data_percent is 0
|
||||
ansible.builtin.assert:
|
||||
that: volume_data_percent|float == 0.0
|
||||
fail_msg: "Volume data percent is {{ volume_data_percent }} while it should be 0"
|
||||
always:
|
||||
- name: Cleanup
|
||||
ansible.builtin.include_tasks: post-test-tasks.yml
|
@ -0,0 +1,32 @@
|
||||
- name: Test removing snapshots after creating them
|
||||
hosts: all
|
||||
become: true
|
||||
vars:
|
||||
volume_group: test_vg
|
||||
volumes:
|
||||
- name: test_lv
|
||||
size: 1g
|
||||
directory: /mnt/test
|
||||
snapshot_set_name: demo_snap
|
||||
snapshot_create_snapshot_autoextend_threshold: 80
|
||||
snapshot_create_snapshot_autoextend_percent: 15
|
||||
tasks:
|
||||
- name: Run pre-test steps
|
||||
ansible.builtin.include_tasks: pre-test-tasks.yml
|
||||
|
||||
- name: Create the snapshot
|
||||
ansible.builtin.include_tasks: create-snapshot.yml
|
||||
|
||||
- name: Remove Snapshot
|
||||
vars:
|
||||
snapshot_remove_set_name: "{{ snapshot_set_name }}"
|
||||
ansible.builtin.include_role:
|
||||
name: snapshot_remove
|
||||
|
||||
- name: Verify that the snapshot no longer exist
|
||||
vars:
|
||||
volume_name: test_lv
|
||||
ansible.builtin.include_tasks: verify-snapshot-not-exist.yml
|
||||
|
||||
- name: Cleanup
|
||||
ansible.builtin.include_tasks: post-test-tasks.yml
|
@ -0,0 +1,63 @@
|
||||
- name: Test revering to the snapshots
|
||||
hosts: all
|
||||
become: true
|
||||
vars:
|
||||
volume_group: test_vg
|
||||
test_directory: "/mnt/test"
|
||||
volumes:
|
||||
- name: test_lv
|
||||
size: 1g
|
||||
directory: "{{ test_directory }}"
|
||||
test_file: "{{ test_directory }}/foo.txt"
|
||||
snapshot_set_name: demo_snap
|
||||
tasks:
|
||||
- name: Run pre-test steps
|
||||
ansible.builtin.include_tasks: pre-test-tasks.yml
|
||||
|
||||
- name: Create the snapshot
|
||||
ansible.builtin.include_tasks: create-snapshot.yml
|
||||
|
||||
- name: Create test file
|
||||
block:
|
||||
- name: Verify that the file does not exist
|
||||
block:
|
||||
- name: Run ls
|
||||
ansible.builtin.command: "ls {{ test_file }}"
|
||||
register: ls_response
|
||||
changed_when: false
|
||||
ignore_errors: true
|
||||
failed_when: ls_response.rc == 0
|
||||
- name: Create the file using touch
|
||||
ansible.builtin.file:
|
||||
path: "{{ test_file }}"
|
||||
state: touch
|
||||
mode: u=rw,g=r,o=r
|
||||
- name: Verify that the file exists
|
||||
block:
|
||||
- name: Run ls
|
||||
ansible.builtin.command: "ls {{ test_file }}"
|
||||
register: ls_response
|
||||
changed_when: false
|
||||
|
||||
- name: Revert to Snapshot
|
||||
vars:
|
||||
snapshot_revert_set_name: "{{ snapshot_set_name }}"
|
||||
ansible.builtin.include_role:
|
||||
name: snapshot_revert
|
||||
|
||||
- name: Verify that the file no longer exist
|
||||
block:
|
||||
- name: Run ls
|
||||
ansible.builtin.command: "ls {{ test_file }}"
|
||||
register: ls_response
|
||||
changed_when: false
|
||||
ignore_errors: true
|
||||
failed_when: ls_response.rc == 0
|
||||
|
||||
- name: Verify that the snapshot no longer exists
|
||||
vars:
|
||||
volume_name: test_lv
|
||||
ansible.builtin.include_tasks: verify-snapshot-not-exist.yml
|
||||
|
||||
- name: Cleanup
|
||||
ansible.builtin.include_tasks: post-test-tasks.yml
|
@ -0,0 +1,39 @@
|
||||
- name: Test trying to create to big a snapshot
|
||||
hosts: all
|
||||
become: true
|
||||
vars:
|
||||
volume_group: test_vg
|
||||
volumes:
|
||||
- name: test_lv
|
||||
size: 8g
|
||||
directory: /mnt/test
|
||||
snapshot_set_name: demo_snap
|
||||
snapshot_create_snapshot_autoextend_threshold: 80
|
||||
snapshot_create_snapshot_autoextend_percent: 15
|
||||
tasks:
|
||||
- name: Run pre-test steps
|
||||
ansible.builtin.include_tasks: pre-test-tasks.yml
|
||||
|
||||
- name: Create the snapshot and handle the failure
|
||||
block:
|
||||
- name: Create the snapshot
|
||||
ansible.builtin.include_tasks: create-snapshot.yml
|
||||
always:
|
||||
- name: Verify that the snapshot does not exist
|
||||
vars:
|
||||
volume_name: test_lv
|
||||
ansible.builtin.include_tasks: verify-snapshot-not-exist.yml
|
||||
- name: Cleanup
|
||||
ansible.builtin.include_tasks: post-test-tasks.yml
|
||||
- name: Print the failure JSON if exists
|
||||
ansible.builtin.debug:
|
||||
var: snapshot_create_check_failure_json
|
||||
when: snapshot_create_check_failure_json is defined
|
||||
- name: Check results
|
||||
ansible.builtin.assert:
|
||||
that:
|
||||
- snapshot_create_check_failure_json is defined
|
||||
- snapshot_create_check_failure_json.test_vg
|
||||
- snapshot_create_check_failure_json.test_vg.size == 9646899200
|
||||
- snapshot_create_check_failure_json.test_vg.free == 1056964608
|
||||
- snapshot_create_check_failure_json.test_vg.requested_size == 8589934592
|
@ -0,0 +1,24 @@
|
||||
- name: Run lvs
|
||||
ansible.builtin.command: lvs --select 'vg_name = {{ volume_group }} && origin = {{ item.name }}' --reportformat json
|
||||
register: lvs_response
|
||||
changed_when: false
|
||||
|
||||
- name: Parse report
|
||||
ansible.builtin.set_fact:
|
||||
lv_snapshot_array: "{{ (lvs_response.stdout | from_json).report[0].lv }}"
|
||||
|
||||
- name: Verify that the the snapshot exists
|
||||
ansible.builtin.assert:
|
||||
that: (lv_snapshot_array | length) == 1
|
||||
fail_msg: >
|
||||
The snapshot for {{ item.name }} was not created
|
||||
|
||||
- name: Get the snapshot name
|
||||
ansible.builtin.set_fact:
|
||||
snapshot_name: "{{ lv_snapshot_array[0].lv_name | default('n/a') }}"
|
||||
|
||||
- name: Verify that the the snapshot was named correctly
|
||||
ansible.builtin.assert:
|
||||
that: snapshot_name == item.name + '_' + snapshot_set_name
|
||||
fail_msg: >
|
||||
Snapshot name '{{ snapshot_name }}' is not as expected {{ item.name }}_{{ snapshot_set_name }}
|
@ -0,0 +1,16 @@
|
||||
- name: Run lvs
|
||||
ansible.builtin.command: lvs --select 'vg_name = {{ volume_group }} && lv_name = {{ volume_name }}_{{ snapshot_set_name }}' --reportformat json
|
||||
register: lvs_response
|
||||
changed_when: false
|
||||
|
||||
- name: Parse report
|
||||
ansible.builtin.set_fact:
|
||||
lv_snapshot_report_array: "{{ (lvs_response.stdout | from_json).report[0].lv }}"
|
||||
|
||||
- name: Verify that the snapshot no longer exists
|
||||
ansible.builtin.assert:
|
||||
that: (lv_snapshot_report_array | length) == 0
|
||||
fail_msg: >
|
||||
The snapshot '{{ volume_name }}_{{ snapshot_set_name }}'' for
|
||||
volume '{{ volume_name }}' in volume group '{{ volume_group }}'
|
||||
still exists
|
Reference in New Issue
Block a user