Skip to content

Commit

Permalink
Split lvm_snapshots role into separate roles (#40)
Browse files Browse the repository at this point in the history
Split into three roles - create, revert and remove
For create allow running only check
Do not use check_for_resize as the functionality was moved to shrink_lv

Signed-off-by: Ygal Blum <[email protected]>
  • Loading branch information
ygalblum authored Jan 3, 2024
1 parent 2aba5c7 commit b608d99
Show file tree
Hide file tree
Showing 28 changed files with 318 additions and 368 deletions.
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,9 @@ This collection depends on the following collections
These are the roles included in the collection. Follow the links below to see the detailed documentation and example playbooks for each role.
- [`lvm_snapshots`](./roles/lvm_snapshots/) - controls creation and rollback for a defined set of LVM snapshot volumes
- [`create_snapshot`](./roles/create_snapshot/) - controls the creation for a defined set of LVM snapshot volumes
- [`remove_snapshot`](./roles/remove_snapshot/) - used to remove snapshots previously created using the `create_snapshot` role
- [`revert_snapshot`](./roles/revert_snapshot/) - used to revert to snapshots previously created using the `create_snapshot` role
- [`shrink_lv`](./roles/shrink_lv/) - controls decreasing logical volume size along with the filesystem
- [`bigboot`](./roles/bigboot/) - controls increasing of the boot partition while moving, and shrinking if needed, the adjacent partition
- [`initramfs`](./roles/initramfs/) - controls the atomic flow of building and using a temporary initramfs in a reboot and restoring the original one
Expand Down
2 changes: 2 additions & 0 deletions changelogs/fragments/split-lvm-snapshot_role.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
breaking_changes:
- Split lvm_snapshots role into create_snapshot, revert_snapshot and remove_snapshot
84 changes: 84 additions & 0 deletions roles/create_snapshot/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
# create_snapshot role


The `create_snapshot` role is used to control the creation for a defined set of LVM snapshot volumes.
In addition, it can optionally save the Grub configuration and image files under /boot and configure settings to enable the LVM snapshot autoextend capability.
The role will verify free space and should fail if there is not enough or if any snapshots already exist for the given `create_snapshot_set_name`.

The role is designed to support the automation of RHEL in-place upgrades, but can also be used to reduce the risk of more mundane system maintenance activities.

## Role Variables

### `create_snapshot_check_only`

When set to `true` the role will only verify there is enough free space for the specified snapshots and not create them.
Default `false`

### `create_snapshot_set_name`

The variable `create_snapshot_set_name` is used to identify the list of volumes to be operated upon.
The role will use the following naming convention when creating the snapshots:

`<Origin LV name>_<create_snapshot_set_name>`

### `create_snapshot_boot_backup`

Boolean to specify that the role should preserve the Grub configuration and image files under /boot required for booting the default kernel.
The files are preserved in a compressed tar archive at `/root/boot-backup-<create_snapshot_set_name>.tgz`. Default is `false`.

> **Warning**
>
> When automating RHEL in-place upgrades, do not perform a Grub to Grub2 migration as part of your upgrade playbook. It will invalidate your boot backup and cause a subsequent `revert` action to fail. For example, if you are using the [`upgrade`](https://github.com/redhat-cop/infra.leapp/tree/main/roles/upgrade#readme) role from the [`infra.leapp`](https://github.com/redhat-cop/infra.leapp) collection, do not set `update_grub_to_grub_2` to `true`. Grub to Grub2 migration should only be performed after the `remove` action has been performed to delete the snapshots and boot backup.
### `create_snapshot_snapshot_autoextend_threshold`

Configure the given `create_snapshot_autoextend_threshold` setting in lvm.conf before creating snapshots.

### `create_snapshot_snapshot_autoextend_percent`

Configure the given `create_snapshot_snapshot_autoextend_percent` setting in lvm.conf before creating snapshots.

### `create_snapshot_volumes`

This is the list of logical volumes for which snapshots are to be created and the size requirements for those snapshots. The volumes list is only required when the role is run with the check or create action.

### `vg`

The volume group of the origin logical volume for which a snapshot will be created.

### `lv`

The origin logical volume for which a snapshot will be created.

### `size`

The size of the logical volume according to the definition of the
[size](https://docs.ansible.com/ansible/latest/collections/community/general/lvol_module.html#parameter-size)
parameter of the `community.general.lvol` module.

To create thin provisioned snapshot of a thin provisioned volume, omit the `size` parameter or set it to `0`

## Example Playbooks

Perform space check and fail of there will not be enough space for all the snapshots in the set.
If there is sufficient space, proceed to create snapshots for the listed logical volumes.
Each snapshot will be sized to 20% of the origin volume size.
Snapshot autoextend settings are configured to enable free space in the volume group to be allocated to any snapshot that may exceed 70% usage in the future.
Files under /boot will be preserved.

```yaml
- hosts: all
roles:
- name: create_snapshot
create_snapshot_set_name: ripu
create_snapshot_snapshot_autoextend_threshold: 70
create_snapshot_snapshot_autoextend_percent: 20
create_snapshot_boot_backup: true
create_snapshot_volumes:
- vg: rootvg
lv: root
size: 2G
- vg: rootvg
lv: var
size: 2G
```
2 changes: 2 additions & 0 deletions roles/create_snapshot/defaults/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
create_snapshot_volumes: []
create_snapshot_boot_backup: false
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,26 +1,26 @@
- name: Verify that all volumes exist
ansible.builtin.include_tasks: verify_volume_exists.yml
loop: "{{ lvm_snapshots_volumes }}"
loop: "{{ create_snapshot_volumes }}"

- name: Verify that there are no existing snapshots
ansible.builtin.include_tasks: verify_no_existing_snapshot.yml
loop: "{{ lvm_snapshots_volumes }}"
loop: "{{ create_snapshot_volumes }}"

- name: Verify that there is enough storage space
ansible.builtin.script: check.py snapshots '{{ lvm_snapshots_volumes | to_json }}'
ansible.builtin.script: check.py snapshots '{{ create_snapshot_volumes | to_json }}'
args:
executable: "{{ ansible_python.executable }}"
register: lvm_snapshots_check_status
register: create_snapshot_check_status
failed_when: false
changed_when: false

- name: Store check return in case of failure
ansible.builtin.set_fact:
lvm_snapshots_check_failure_json: "{{ lvm_snapshots_check_status.stdout | from_json }}"
when: lvm_snapshots_check_status.rc != 0
create_snapshot_check_failure_json: "{{ create_snapshot_check_status.stdout | from_json }}"
when: create_snapshot_check_status.rc != 0

- name: Assert results
ansible.builtin.assert:
that: lvm_snapshots_check_status.rc == 0
that: create_snapshot_check_status.rc == 0
fail_msg: Not enough space in the Volume Groups to create the requested snapshots
success_msg: The Volume Groups have enough space to create the requested snapshots
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,21 @@
block:
- name: Stringify snapshot_autoextend_percent setting
ansible.builtin.set_fact:
lvm_snapshots_snapshot_autoextend_percent_config: "activation/snapshot_autoextend_percent={{ lvm_snapshots_snapshot_autoextend_percent }}"
when: lvm_snapshots_snapshot_autoextend_percent is defined
create_snapshot_snapshot_autoextend_percent_config: "activation/snapshot_autoextend_percent={{ create_snapshot_snapshot_autoextend_percent }}"
when: create_snapshot_snapshot_autoextend_percent is defined
- name: Stringify snapshot_autoextend_threshold setting
ansible.builtin.set_fact:
lvm_snapshots_snapshot_autoextend_threshold_config: "activation/snapshot_autoextend_threshold={{ lvm_snapshots_snapshot_autoextend_threshold }}"
when: lvm_snapshots_snapshot_autoextend_threshold is defined
create_snapshot_snapshot_autoextend_threshold_config: "activation/snapshot_autoextend_threshold={{ create_snapshot_snapshot_autoextend_threshold }}"
when: create_snapshot_snapshot_autoextend_threshold is defined
- name: Stringify the new config
ansible.builtin.set_fact:
lvm_snapshots_new_lvm_config: >
{{ lvm_snapshots_snapshot_autoextend_percent_config | default('') }}
{{ lvm_snapshots_snapshot_autoextend_threshold_config | default('') }}
create_snapshot_new_lvm_config: >
{{ create_snapshot_snapshot_autoextend_percent_config | default('') }}
{{ create_snapshot_snapshot_autoextend_threshold_config | default('') }}
- name: Set LVM configuration
ansible.builtin.command: 'lvmconfig --mergedconfig --config "{{ lvm_snapshots_new_lvm_config }}" --file /etc/lvm/lvm.conf'
ansible.builtin.command: 'lvmconfig --mergedconfig --config "{{ create_snapshot_new_lvm_config }}" --file /etc/lvm/lvm.conf'
changed_when: true
when: ((lvm_snapshots_new_lvm_config | trim) | length) > 0
when: ((create_snapshot_new_lvm_config | trim) | length) > 0

- name: Check for grubenv saved_entry
ansible.builtin.lineinfile:
Expand All @@ -26,20 +26,20 @@
check_mode: true
changed_when: false
failed_when: false
register: grubenv
register: create_snapshot_grubenv

- name: Add grubenv saved_entry
ansible.builtin.shell: 'grubby --set-default-index=$(grubby --default-index)'
changed_when: true
when: grubenv.found is defined and grubenv.found == 0
when: create_snapshot_grubenv.found is defined and create_snapshot_grubenv.found == 0

- name: Create snapshots
community.general.lvol:
vg: "{{ item.vg }}"
lv: "{{ item.lv }}"
snapshot: "{{ item.lv }}_{{ lvm_snapshots_set_name }}"
snapshot: "{{ item.lv }}_{{ create_snapshot_set_name }}"
size: "{{ item.size | default(omit) }}"
loop: "{{ lvm_snapshots_volumes }}"
loop: "{{ create_snapshot_volumes }}"

- name: Required packages are present
ansible.builtin.package:
Expand All @@ -52,7 +52,7 @@
community.general.archive:
format: gz
mode: '0644'
dest: "/root/boot-backup-{{ lvm_snapshots_set_name }}.tgz"
dest: "/root/boot-backup-{{ create_snapshot_set_name }}.tgz"
path:
- "/boot/initramfs-{{ ansible_kernel }}.img"
- "/boot/vmlinuz-{{ ansible_kernel }}"
Expand All @@ -65,4 +65,4 @@
- /boot/grub2/grubenv
- /boot/loader/entries
- /boot/efi/EFI/redhat/grub.cfg
when: lvm_snapshots_boot_backup
when: create_snapshot_boot_backup
8 changes: 8 additions & 0 deletions roles/create_snapshot/tasks/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
- name: Check available disk space
ansible.builtin.include_tasks: check.yml

- name: Create Snapshot
vars:
create_snapshot_volumes: "{{ create_snapshot_check_status.stdout | from_json }}"
ansible.builtin.include_tasks: create.yml
when: not (create_snapshot_check_only | default(false))
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,19 @@
lvs
--select 'vg_name = {{ item.vg }}
&& origin = {{ item.lv }}
&& lv_name = {{ item.lv }}_{{ lvm_snapshots_set_name }}'
&& lv_name = {{ item.lv }}_{{ create_snapshot_set_name }}'
--reportformat json
register: lvm_snapshots_lvs_response
register: create_snapshot_lvs_response
changed_when: false

- name: Parse report
ansible.builtin.set_fact:
lvm_snapshots_lv_snapshot_report_array: "{{ (lvm_snapshots_lvs_response.stdout | from_json).report[0].lv }}"
create_snapshot_lv_snapshot_report_array: "{{ (create_snapshot_lvs_response.stdout | from_json).report[0].lv }}"

- name: Verify that the no snapshot exists for the volume
ansible.builtin.assert:
that: (lvm_snapshots_lv_snapshot_report_array | length) == 0
that: (create_snapshot_lv_snapshot_report_array | length) == 0
fail_msg: >
The volume '{{ item.lv }}' in volume group '{{ item.vg }}'
already has at least one snapshot
'{{ lvm_snapshots_lv_snapshot_report_array[0].lv_name | default('none') }}'
'{{ create_snapshot_lv_snapshot_report_array[0].lv_name | default('none') }}'
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
- name: Run lvs
ansible.builtin.command: "lvs --select 'vg_name = {{ item.vg }} && lv_name = {{ item.lv }}' --reportformat json"
register: lvm_snapshots_lvs_response
register: create_snapshot_lvs_response
changed_when: false

- name: Verify that the volume was found
ansible.builtin.assert:
that: (((lvm_snapshots_lvs_response.stdout | from_json).report[0].lv) | length) > 0
that: (((create_snapshot_lvs_response.stdout | from_json).report[0].lv) | length) > 0
fail_msg: "Could not find volume '{{ item.lv }}' in volume group '{{ item.vg }}'"
115 changes: 0 additions & 115 deletions roles/lvm_snapshots/README.md

This file was deleted.

2 changes: 0 additions & 2 deletions roles/lvm_snapshots/defaults/main.yml

This file was deleted.

Loading

0 comments on commit b608d99

Please sign in to comment.