Skip to content

Commit

Permalink
Add preflight OS checks
Browse files Browse the repository at this point in the history
- Implemented OS preflight checks to validate system requirements before Ceph cluster creation.
- Checks include:
  - OS version (RHEL 9+ required)
  - SELinux enforcing mode
  - Firewalld installation and status
  - Required package availability (rpcbind, podman, firewalld)
  - Podman version check (>= 3.3)
  - RHEL software profile validation
  - Tuned profile check
  • Loading branch information
Kushal-deb committed Feb 5, 2025
1 parent 1d3efbc commit 280a9cf
Showing 1 changed file with 199 additions and 0 deletions.
199 changes: 199 additions & 0 deletions cephadm-preflight.yml
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,205 @@
- name: redhat family of OS related tasks
when: ansible_facts['os_family'] == 'RedHat'
block:
- name: Initialize os_check variable
set_fact:
os_check: { "failed": false }

- name: OS Preflight Checks
block:
- name: Initialize check results
set_fact:
preflight_results: []

- name: Ensure OS is RHEL 9+
fail:
msg: "Ceph requires RHEL 9+. Detected: {{ ansible_facts['distribution'] }} {{ ansible_facts['distribution_version'] }}"
when:
- ansible_facts['distribution'] not in ['RedHat'] or ansible_facts['distribution_major_version'] | int < 9
register: os_check
ignore_errors: true

- name: Store OS check result
set_fact:
preflight_results: "{{ preflight_results + [{'Check': 'OS Version', 'Result': 'PASS' if ansible_facts['distribution_major_version'] | int >= 9 else 'FAIL'}] }}"

- name: Ensure SELinux is set to Enforcing mode
ansible.posix.selinux:
policy: targeted
state: enforcing
register: selinux_status
changed_when: false
failed_when: selinux_status.state != 'enforcing'

- name: Store SELinux check result
set_fact:
preflight_results: "{{ preflight_results + [
{
'Check': 'SELinux',
'Result': 'PASS' if selinux_status.state == 'enforcing' else 'FAIL',
'Reason': 'SELinux was not in enforcing mode and could not be enforced automatically' if selinux_status.failed else 'N/A'
}
] }}"

- name: Ensure required packages are installed
package:
name:
- rpcbind
- podman
- firewalld
state: present

- name: Ensure firewalld is enabled and running
systemd:
name: firewalld
state: started
enabled: true
register: firewall_status
failed_when: firewall_status.status.ActiveState != "active"

- name: Fail if firewalld is not running
fail:
msg: "Firewalld is required for ceph but is not running"
when: firewall_status.status.ActiveState != "active"
register: firewall_fail

- name: Store Firewalld check result
set_fact:
preflight_results: "{{ preflight_results + [{'Check': 'Firewalld Running', 'Result': 'PASS' if firewall_status is succeeded else 'FAIL'}] }}"

- name: Initialize Podman installation status
set_fact:
podman_installed: false
podman_path: ""
podman_version: "NOT_INSTALLED"

- name: Check if Podman is installed
shell: "command -v podman || echo 'NOT_FOUND'"
register: podman_path_raw
changed_when: false
ignore_errors: true

- name: Set Podman installation status
set_fact:
podman_installed: "{{ podman_path_raw.stdout != 'NOT_FOUND'}}"
podman_path: "{{ podman_path_raw.stdout if podman_path_raw.stdout != 'NOT_FOUND' else '' }}"

- name: Debug Podman Path
debug:
msg: "Podman is installed at: {{ podman_path}}"

- name: Extract Podman version
shell: "podman --version | awk '{print $3}'"
register: podman_version_raw
changed_when: false
ignore_errors: true
when: podman_installed

- name: Set Podman version fact
set_fact:
podman_version: "{{ podman_version_raw.stdout if podman_installed else 'NOT_INSTALLED' }}"

- name: Check if podman version is less than 3.3
fail:
msg: "Podman version must be >=3.3, but detected: {{ podman_version }}"
when:
- podman_installed
- podman_version is version('3.3', '<')
register: podman_fail

- name: Store Podman version check
set_fact:
preflight_results: "{{ preflight_results + [{'Check': 'Podman Version >= 3.3', 'Result': 'PASS' if podman_version_raw.stdout is defined and podman_version_raw.stdout is version('3.3', '>=') else 'FAIL'}] }}"

- name: check RHEL software profile
command: subscription-manager list --consumed
register: rhel_profile
changed_when: false

- name: Debug RHEL profile
debug:
msg: "Detected RHEL Profile: {{ rhel_profile.stdout }}"

- name: Validate RHEL software profile
set_fact:
rhel_profile_valid: "{{ 'Server' in rhel_profile.stdout and 'File and Storage Server' in rhel_profile.stdout }}"

- name: Store RHEL Profile check
set_fact:
preflight_results: "{{ preflight_results + [
{
'Check': 'RHEL Profile',
'Result': 'PASS' if rhel_profile_valid else 'FAIL',
'Reason': 'Incorrect RHEL software profile. Expected: Server with File and Storage Server, but detected: ' ~ (rhel_profile.stdout | default('UNKNOWN'))
}
] }}"

- name: Get current tuned profile
command: tuned-adm active
register: tuned_profile
changed_when: false
failed_when: false

- name: Debug tuned profile output
debug:
msg: "Detected tuned profile: {{ tuned_profile.stdout | default('UNKNOWN') }}"

- name: Fail if tuned profile is incorrect
fail:
msg: "Incorrect tuned profile. Expected: 'throughput-performance', but detected: {{ tuned_profile.stdout }}"
when: "'throughput-performance' not in tuned_profile.stdout"
register: tuned_fail

- name: Store Tuned Profile Check
set_fact:
preflight_results: "{{ preflight_results + [{'Check': 'Tuned Profile', 'Result': 'FAIL' if tuned_fail.failed else 'PASS', 'Reason': tuned_fail.msg if tuned_fail.failed else 'N/A'}] }}"

- name: Ensure the templates directory exists
delegate_to: localhost
run_once: true
become: false
file:
path: templates
state: directory
mode: '0755'

- name: Check if preflight report template exists
delegate_to: localhost
run_once: true
become: false
stat:
path: templates/preflight_report.j2
register: template_stat

- name: Create the preflight report template if missing
delegate_to: localhost
run_once: true
become: false
copy:
dest: templates/preflight_report.j2
content: |
Preflight Check Report
======================
{% for item in preflight_results %}
- {{ item['Check'] }}: {{ item['Result'] }}
{% if item['Result'] == 'FAIL' and item['Reason'] != 'N/A' %}
-> Reason: {{ item['Reason'] }}
{% endif %}
{% endfor %}
when: not template_stat.stat.exists

- name: Generate preflight check report
delegate_to: localhost
run_once: true
become: false
template:
src: templates/preflight_report.j2
dest: ./ceph_preflight_report.txt

- name: Notify user about report location
debug:
msg: "Preflight check report has been generated at ./ceph_preflight_report.txt (local machine)"

- name: rhcs related tasks
when: ceph_origin == 'rhcs'
block:
Expand Down

0 comments on commit 280a9cf

Please sign in to comment.