From 01c0e21f94af7c88282df46129eddc9ea48eafc1 Mon Sep 17 00:00:00 2001 From: Ethan Paul Date: Wed, 10 Nov 2021 00:22:43 -0500 Subject: [PATCH] Add datastore role for validating config of datastore setup --- playbooks/configure.yaml | 2 + roles/datastore/tasks/gluster.yaml | 45 ++++++++++++ roles/datastore/tasks/main.yaml | 9 +++ roles/datastore/tasks/mounts.yaml | 108 ++++++++++++++++++++++++++++ roles/datastore/tasks/packages.yaml | 31 ++++++++ 5 files changed, 195 insertions(+) create mode 100644 roles/datastore/tasks/gluster.yaml create mode 100644 roles/datastore/tasks/main.yaml create mode 100644 roles/datastore/tasks/mounts.yaml create mode 100644 roles/datastore/tasks/packages.yaml diff --git a/playbooks/configure.yaml b/playbooks/configure.yaml index 9e8df61..13e5097 100644 --- a/playbooks/configure.yaml +++ b/playbooks/configure.yaml @@ -21,3 +21,5 @@ roles: - role: server when: "'server' in skylab_roles | default([])" + - role: datastore + when: "'datastore' in skylab_roles | default([])" diff --git a/roles/datastore/tasks/gluster.yaml b/roles/datastore/tasks/gluster.yaml new file mode 100644 index 0000000..4160510 --- /dev/null +++ b/roles/datastore/tasks/gluster.yaml @@ -0,0 +1,45 @@ +--- +- name: Allow gluster through firewall + become: true + ansible.posix.firewalld: + service: glusterfs + state: enabled + zone: trusted + immediate: true + permanent: true + +- name: Create datastore directory + become: true + ansible.builtin.file: + path: /mnt/brick/datastore + state: directory + +- name: Fetch peer status + become: true + ansible.builtin.command: + cmd: gluster peer status + changed_when: false + register: _gluster_peer_status_raw + +- name: Check peer status + ansible.builtin.assert: + that: + - not _gluster_peer_status_raw.stdout_lines[0].strip().endswith('0') + fail_msg: >- + ERROR: Datastore host '{{ inventory_hostname }}' is not joined to the gluster pool. Run the + command 'gluster peer probe {{ inventory_hostname }}.local' from another datastore host to + add it. + success_msg: >- + Datastore host {{ inventory_hostname }} is joined to the gluster pool + +- name: Mount gluster volume + become: true + ansible.posix.mount: + path: /mnt/datastore + src: localhost:/datastore + state: mounted + fstype: glusterfs + # Note that this just needs to be any path *other* than the actual + # fstab. This is done just to prevent the devices from being + # automatically mounted at boot + fstab: "{{ skylab_state_dir }}/mounts" diff --git a/roles/datastore/tasks/main.yaml b/roles/datastore/tasks/main.yaml new file mode 100644 index 0000000..6d5396a --- /dev/null +++ b/roles/datastore/tasks/main.yaml @@ -0,0 +1,9 @@ +--- +- name: Install datastore packages + ansible.builtin.import_tasks: packages.yaml + +- name: Configure mounting + ansible.builtin.import_tasks: mounts.yaml + +- name: Configure glusterfs + ansible.builtin.import_tasks: gluster.yaml diff --git a/roles/datastore/tasks/mounts.yaml b/roles/datastore/tasks/mounts.yaml new file mode 100644 index 0000000..3986db0 --- /dev/null +++ b/roles/datastore/tasks/mounts.yaml @@ -0,0 +1,108 @@ +--- +- name: Create mount points + become: true + ansible.builtin.file: + path: "{{ item }}" + state: directory + mode: 0755 + owner: root + group: "{{ ansible_user }}" + loop: + - /mnt/datastore + - /mnt/brick + +- name: Determine current mounts + vars: + _current_mounts: [] + ansible.builtin.set_fact: + _current_mounts: "{{ _current_mounts + [item.mount] }}" + loop: "{{ ansible_mounts }}" + loop_control: + label: "{{ item.mount }}" + +- name: Ensure mount points are empty when unmounted + when: item not in _current_mounts + ansible.builtin.command: + cmd: "/usr/bin/ls {{ item }}" + changed_when: false + failed_when: _mountpoint_ls_raw.stdout + register: _mountpoint_ls_raw + loop: + - /mnt/datastore + - /mnt/brick + +- name: Fetch block device information + ansible.builtin.command: + cmd: lsblk /dev/{{ skylab_datastore_device }} --fs --json + changed_when: false + register: _lsblk_info_raw + +- name: Process block device information + ansible.builtin.set_fact: + _datastore_device_info: "{{ (_lsblk_info_raw.stdout | from_json).blockdevices[0] }}" + +- name: Check state of the datastore device + ansible.builtin.assert: + that: _datastore_device_info.fstype == "crypto_LUKS" + fail_msg: >- + ERROR: Datastore block device {{ inventory_hostname }}:/dev/{{ skylab_datastore_device }} + must be LUKS encrypted + success_msg: >- + Datastore block device {{ inventory_hostname }}:/dev/{{ skylab_datastore_device }} is + LUKS encrypted + +- name: Determine whether datastore block is decrypted + ansible.builtin.set_fact: + _datastore_device_is_decrypted: "{{ _datastore_device_info.children is defined }}" + +- name: Decrypt datastore block + when: not _datastore_device_is_decrypted + block: + - name: Prompt for decryption key + no_log: true + ansible.builtin.pause: + prompt: >- + Datastore device {{ inventory_hostname }}:/dev/{{ skylab_datastore_device }} is not + decrypted. Enter decryption passphrase to continue GlusterFS brick configuration + echo: false + register: _luks_decryption_key + + - name: Open LUKS device + become: true + community.crypto.luks_device: + device: /dev/{{ skylab_datastore_device }} + state: opened + name: brick + passphrase: "{{ _luks_decryption_key.user_input }}" + + - name: Fetch updated block device information + ansible.builtin.command: + cmd: lsblk /dev/{{ skylab_datastore_device }} --fs --json + changed_when: false + register: _lsblk_info_raw + + - name: Process updated block device information + ansible.builtin.set_fact: + _datastore_device_info: "{{ (_lsblk_info_raw.stdout | from_json).blockdevices[0] }}" + +- name: Create dummy fstab + ansible.builtin.file: + state: touch + path: "{{ skylab_state_dir }}/mounts" + owner: "{{ ansible_user }}" + group: "{{ ansible_user }}" + mode: 0644 + access_time: preserve + modification_time: preserve + +- name: Mount datastore block + become: true + ansible.posix.mount: + path: /mnt/brick + src: UUID={{ _datastore_device_info.children[0].uuid }} + state: mounted + fstype: "{{ _datastore_device_info.children[0].fstype }}" + # Note that this just needs to be any path *other* than the actual + # fstab. This is done just to prevent the devices from being + # automatically mounted at boot + fstab: "{{ skylab_state_dir }}/mounts" diff --git a/roles/datastore/tasks/packages.yaml b/roles/datastore/tasks/packages.yaml new file mode 100644 index 0000000..d520911 --- /dev/null +++ b/roles/datastore/tasks/packages.yaml @@ -0,0 +1,31 @@ +--- +- name: Install gluster repository + become: true + ansible.builtin.dnf: + name: centos-release-gluster9 + state: present + register: _datastore_repo_gluster + +- name: Enable required repositories + become: true + ansible.builtin.lineinfile: + path: /etc/yum.repos.d/{{ item }}.repo + line: enabled=1 + state: present + regexp: "#?enabled=(0|1)" + loop: + - Rocky-AppStream + - Rocky-PowerTools + register: _datastore_repo_powertools + +- name: Install datastore packages + become: true + when: ansible_distribution == "Rocky" + ansible.builtin.dnf: + state: present + update_cache: "{{ _datastore_repo_powertools.changed or _datastore_repo_gluster.changed }}" + name: + - cryptsetup-luks + - glusterfs + - glusterfs-fuse + - glusterfs-server