Skip to content

Commit

Permalink
feat: expose ha_cluster_info module via role variables
Browse files Browse the repository at this point in the history
  • Loading branch information
tomjelinek committed Nov 28, 2024
1 parent 5cf96e5 commit 2078300
Show file tree
Hide file tree
Showing 13 changed files with 277 additions and 86 deletions.
84 changes: 63 additions & 21 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,7 @@ An Ansible role for managing High Availability Clustering.
* Pacemaker Access Control Lists (ACLs)
* node and resource utilization
* Pacemaker Alerts
* The role provides `ha_cluster_info` module which exports current cluster
configuration. The module is capable of exporting:
* The role is capable of exporting existing cluster configuration:
* single-link or multi-link cluster
* Corosync transport options including compression and encryption
* Corosync totem options
Expand Down Expand Up @@ -65,6 +64,13 @@ ansible-galaxy collection install -r meta/collection-requirements.yml

### Defined in `defaults/main.yml`

#### `ha_cluster_get_info`

boolean, default: `false`

Export existing cluster configuration. See
[Variables Exported by the Role](#variables-exported-by-the-role) for details.

#### `ha_cluster_enable_repos`

boolean, default: `true`
Expand Down Expand Up @@ -125,7 +131,7 @@ boolean, default: `true`

If set to `true`, HA cluster will be configured on the hosts according to other
variables. If set to `false`, all HA Cluster configuration will be purged from
target hosts.
target hosts. If set to `null`, HA cluster configuration will not be changed.

#### `ha_cluster_start_on_boot`

Expand Down Expand Up @@ -1462,6 +1468,9 @@ for clusters. The items are as follows:
Note that you cannot run qnetd on a cluster node as fencing would disrupt qnetd
operation.

If you set `ha_cluster_qnetd: null`, then qnetd host configuration will not be
changed.

You may take a look at [an
example](#configuring-a-cluster-using-a-quorum-device).

Expand Down Expand Up @@ -1551,9 +1560,9 @@ all:
monitoring. Defaults to empty list if not set. Always refer to the devices
using the long, stable device name (`/dev/disk/by-id/`).

## Export current cluster configuration
## Variables Exported by the Role

The role provides `ha_cluster_info` module which exports current cluster
The role contains `ha_cluster_info` module which exports current cluster
configuration in a dictionary matching the structure of this role variables. If
the role is run with these variables, it recreates the same cluster.

Expand Down Expand Up @@ -1590,38 +1599,71 @@ may not be present in the export.
responsibility to decide if you want to use existing keys or generate new
ones.

To export current cluster configuration and store it in
`ha_cluster_info_result` variable, write a task like this:
To export current cluster configuration and store it in `ha_cluster_facts`
variable, run the role with `ha_cluster_get_info: true`. This triggers the
export once the role finishes configuring a cluster or a qnetd host. If you
want to trigger the export without modifying existing configuration, run the
role like this:

```yaml
- name: Get current cluster configuration
linux-system-roles.ha_cluster.ha_cluster_info:
register: ha_cluster_info_result
- hosts: node1
vars:
ha_cluster_cluster_present: null
ha_cluster_qnetd: null
ha_cluster_get_info: true
roles:
- linux-system-roles.ha_cluster
```

Then you may use the `ha_cluster_info_result` variable in your playbook
depending on your needs.
**Note:** By default, `ha_cluster_cluster_present` is set to `true` and
`ha_cluster_qnetd.present` is set to `false`. If you do not set the variables as
show in the example above, the role will reconfigure your cluster on the
specified hosts, remove qnetd configuration from the specified hosts, and then
export configuration.

You may use the `ha_cluster_facts` variable in your playbook depending on your
needs.

If you just want to see the content of the variable, use the ansible debug
module like this:

```yaml
- name: Print ha_cluster_info_result variable
debug:
var: ha_cluster_info_result
- hosts: node1
vars:
ha_cluster_cluster_present: null
ha_cluster_qnetd: null
ha_cluster_get_info: true
roles:
- linux-system-roles.ha_cluster
tasks:
- name: Print ha_cluster_info_result variable
debug:
var: ha_cluster_facts
```

Or you may want to save the configuration to a file on your controller node in
YAML format with a task similar to this one, so that you can write a playbook
around it:

```yaml
- name: Save current cluster configuration to a file
delegate_to: localhost
copy:
content: "{{
ha_cluster_info_result.ha_cluster | to_nice_yaml(sort_keys=false) }}"
dest: /path/to/file
- hosts: node1
vars:
ha_cluster_cluster_present: null
ha_cluster_qnetd: null
ha_cluster_get_info: true
roles:
- linux-system-roles.ha_cluster
tasks:
- name: Save current cluster configuration to a file
delegate_to: localhost
copy:
content: "{{ ha_cluster_facts | to_nice_yaml(sort_keys=false) }}"
dest: /path/to/file
```

## Example Playbooks
Expand Down
2 changes: 2 additions & 0 deletions defaults/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -75,3 +75,5 @@ ha_cluster_qnetd:
present: false
regenerate_keys: false
start_on_boot: true

ha_cluster_get_info: false
23 changes: 23 additions & 0 deletions examples/export.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# SPDX-License-Identifier: MIT
---
- name: Example ha_cluster role invocation - export cluster configuration
hosts: node1
vars:
ha_cluster_cluster_present: null
ha_cluster_qnetd: null
ha_cluster_get_info: true

roles:
- linux-system-roles.ha_cluster

tasks:
- name: Print ha_cluster_info_result variable
debug:
var: ha_cluster_facts

- name: Save current cluster configuration to a file
delegate_to: localhost
copy:
content: "{{ ha_cluster_facts | to_nice_yaml(sort_keys=false) }}"
dest: /path/to/file
mode: "0640"
90 changes: 55 additions & 35 deletions tasks/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,43 +18,47 @@
use: "{{ (__ha_cluster_is_ostree | d(false)) |
ternary('ansible.posix.rhel_rpm_ostree', omit) }}"

- name: Check and prepare role variables
include_tasks: shell_{{ ha_cluster_pacemaker_shell }}/check-and-prepare-role-variables.yml # yamllint disable-line rule:line-length

# The user is created by installing pacemaker packages. We just need to set the
# password.
- name: Provide a password for the hacluster user
- name: Preconfigure hosts
when:
- ha_cluster_hacluster_password | string | length > 0
block:
- name: Generate a password hash
# The arg `-6` means SHA512 based algorithms.
command:
cmd: >-
openssl passwd
-6
-salt {{ ansible_hostname.replace('-', 'x') | quote }}
{{ ha_cluster_hacluster_password | string | quote }}
register: __ha_cluster_openssl_call_result
changed_when: false
no_log: true

- name: Set hacluster password
user:
name: hacluster
password: "{{ __ha_cluster_openssl_call_result.stdout }}"

- name: Configure shell
include_tasks: shell_{{ ha_cluster_pacemaker_shell }}/configure-shell.yml # yamllint disable-line rule:line-length

- name: Configure firewall and selinux
when: ha_cluster_cluster_present | bool or ha_cluster_qnetd.present | d(false)
- ha_cluster_cluster_present is not none or ha_cluster_qnetd is not none
block:
- name: Configure firewall
include_tasks: firewall.yml
- name: Check and prepare role variables
include_tasks: shell_{{ ha_cluster_pacemaker_shell }}/check-and-prepare-role-variables.yml # yamllint disable-line rule:line-length

- name: Configure selinux
include_tasks: selinux.yml
# The user is created by installing pacemaker packages. We just need to set
# the password.
- name: Provide a password for the hacluster user
when:
- ha_cluster_hacluster_password | string | length > 0
block:
- name: Generate a password hash
# The arg `-6` means SHA512 based algorithms.
command:
cmd: >-
openssl passwd
-6
-salt {{ ansible_hostname.replace('-', 'x') | quote }}
{{ ha_cluster_hacluster_password | string | quote }}
register: __ha_cluster_openssl_call_result
changed_when: false
no_log: true

- name: Set hacluster password
user:
name: hacluster
password: "{{ __ha_cluster_openssl_call_result.stdout }}"

- name: Configure shell
include_tasks: shell_{{ ha_cluster_pacemaker_shell }}/configure-shell.yml

- name: Configure firewall and selinux
when: ha_cluster_cluster_present | bool or ha_cluster_qnetd.present | d(false) # yamllint disable-line rule:line-length
block:
- name: Configure firewall
include_tasks: firewall.yml

- name: Configure selinux
include_tasks: selinux.yml

- name: Install and configure HA cluster
when: ha_cluster_cluster_present | bool
Expand Down Expand Up @@ -112,7 +116,9 @@
run_once: true

- name: Remove cluster configuration
when: not ha_cluster_cluster_present
when:
- ha_cluster_cluster_present is not none
- not ha_cluster_cluster_present
block:
- name: Remove cluster configuration
include_tasks: shell_{{ ha_cluster_pacemaker_shell }}/cluster-destroy-{{ __ha_cluster_pcs_provider }}.yml # yamllint disable-line rule:line-length
Expand All @@ -123,4 +129,18 @@
state: absent

- name: Configure qnetd
when: ha_cluster_qnetd is not none
include_tasks: shell_{{ ha_cluster_pacemaker_shell }}/pcs-qnetd.yml

- name: Export configuration
when:
- ha_cluster_get_info | bool
- ha_cluster_pacemaker_shell == "pcs"
block:
- name: Fetch configuration
ha_cluster_info:
register: __ha_cluster_info

- name: Set configuration fact
set_fact:
ha_cluster_facts: "{{ __ha_cluster_info.ha_cluster }}"
10 changes: 10 additions & 0 deletions tasks/shell_pcs/check-and-prepare-role-variables.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,15 @@
# SPDX-License-Identifier: MIT
---
- name: Fail if 'cluster present' and 'qnetd present' are inconsistent
fail:
msg: >
Both 'ha_cluster_cluster_present' and 'ha_cluster_qnetd' must be either
defined or set to null
when: >
(ha_cluster_cluster_present is none and ha_cluster_qnetd is not none)
or
(ha_cluster_cluster_present is not none and ha_cluster_qnetd is none)
- name: Discover cluster node names
set_fact:
__ha_cluster_node_name: "{{ ha_cluster.node_name | d(inventory_hostname) }}"
Expand Down
7 changes: 2 additions & 5 deletions tests/tests_cluster_advanced_knet_full.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
hosts: all
vars_files: vars/main.yml
vars:
ha_cluster_get_info: true
ha_cluster_cluster_name: test-cluster
ha_cluster_transport:
type: knet
Expand Down Expand Up @@ -124,15 +125,11 @@
- name: Check firewall and selinux state
include_tasks: tasks/check_firewall_selinux.yml

- name: Export cluster configuration
ha_cluster_info:
register: __test_info

- name: Check exported configuration
vars:
__test_exported_config: >
{{
__test_info.ha_cluster | combine({
ha_cluster_facts | combine({
'ha_cluster_node_options': 'it depends on test environment'
})
}}
Expand Down
7 changes: 2 additions & 5 deletions tests/tests_cluster_advanced_knet_implicit.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
hosts: all
vars_files: vars/main.yml
vars:
ha_cluster_get_info: true
ha_cluster_cluster_name: test-cluster
ha_cluster_transport:
crypto:
Expand Down Expand Up @@ -62,15 +63,11 @@
- name: Check firewall and selinux state
include_tasks: tasks/check_firewall_selinux.yml

- name: Export cluster configuration
ha_cluster_info:
register: __test_info

- name: Check exported configuration
vars:
__test_exported_config: >
{{
__test_info.ha_cluster | combine({
ha_cluster_facts | combine({
'ha_cluster_node_options': 'it depends on test environment'
})
}}
Expand Down
7 changes: 2 additions & 5 deletions tests/tests_cluster_advanced_udp_full.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
hosts: all
vars_files: vars/main.yml
vars:
ha_cluster_get_info: true
ha_cluster_cluster_name: test-cluster
ha_cluster_transport:
type: udp
Expand Down Expand Up @@ -86,15 +87,11 @@
- name: Check firewall and selinux state
include_tasks: tasks/check_firewall_selinux.yml

- name: Export cluster configuration
ha_cluster_info:
register: __test_info

- name: Check exported configuration
vars:
__test_exported_config: >
{{
__test_info.ha_cluster | combine({
ha_cluster_facts | combine({
'ha_cluster_node_options': 'it depends on test environment'
})
}}
Expand Down
Loading

0 comments on commit 2078300

Please sign in to comment.