- name: Check for required variables
  ansible.builtin.fail:
    msg: "The following variables are required: size, name, key_server, mount_point"
  when:
    - item.size is not defined
    - item.name is not defined
    - item.key_server is not defined
    - item.mount_point is not defined

- name: Set required facts
  ansible.builtin.set_fact:
    encryption_volumes_path: "{{ encryption_volumes_path | default('/var/lib/encrypted_volumes') }}"
    size: "{{ item.size | default(encryption_volumes_default_size) }}"
    fstype: "{{ item.fstype | default('ext4') }}"
    key_server: "{{ item.key_server }}"
    key_file_path: "{{ ansible_env.TMPDIR }}/{{ item.name }}.key"
    disk_image_path: "{{ encryption_volumes_path }}/{{ item.name }}.img"
    device_name: "{{ item.name }}_luks"
    key_fetch_service: "{{ item.name }}_key.service"
    mount_point: "{{ item.mount_point | default('/mnt/' + item.name) }}"
    fetch_key_service_before: "{{ item.fetch_key_service_before | default('') }}"
    fetch_key_service_after: "{{ item.fetch_key_service_after | default('') }}"
    fetch_key_service_wantedby: "{{ item.fetch_key_service_wantedby | default('mulit-user.target') }}"
    mount_service_before: "{{ item.mount_service_before | default('') }}"
    mount_service_wantedby: "{{ item.mount_service_wantedby | default('multi-user.target') }}"
    mount_permission: "{{ item.mount_permission | default('0750') }}"

- name: Set transformed facts
  ansible.builtin.set_fact:
    mount_service: "{{ mount_point | regex_replace('^/', '') | replace('/', '-') }}.mount"

- name: Create disk image '{{ item.name }}'
  become: true
  ansible.builtin.command: |
    fallocate -l {{ size }} {{ disk_image_path }}
  args:
    creates: "{{ disk_image_path }}"
  register: disk_image

- name: Create encrypted volume # noqa no-handler
  when: disk_image is changed
  become: true
  block:
    - name: Read system id
      ansible.builtin.command: |
        read_system_id
      changed_when: false
      register: system_id

    - name: Download key file from Key server
      ansible.builtin.uri:
        url: "{{ key_server }}/{{ system_id.stdout }}"
        dest: "{{ key_file_path }}"
        mode: "0600"
      args:
        creates: "{{ key_file_path }}"

    - name: Format LUKS device
      ansible.builtin.command: |
        cryptsetup -q luksFormat {{ disk_image_path }} {{ key_file_path }}
      changed_when: false

    - name: Open LUKS device with key file
      ansible.builtin.command: |
        cryptsetup luksOpen {{ disk_image_path }} {{ device_name }} -d {{ key_file_path }}
      register: luks_device
      changed_when: false

    - name: Create file system
      ansible.builtin.command: |
        mkfs.{{ fstype }} /dev/mapper/{{ device_name }}
      changed_when: false

    - name: Close LUKS device
      ansible.builtin.command: cryptsetup close {{ device_name }}
      changed_when: false

    - name: Delete key file
      ansible.builtin.file:
        path: "{{ key_file_path }}"
        state: absent

- name: Create mount point
  become: true
  ansible.builtin.file:
    path: "{{ mount_point }}"
    state: directory
    mode: "{{ mount_permission }}"

- name: Create service to fetch key file and open LUKS device
  become: true
  ansible.builtin.copy:
    dest: /etc/systemd/system/{{ key_fetch_service }}
    mode: "0644"
    content: |
      [Unit]
      Description={{ item.name }} key fetch service
      After={{ fetch_key_service_after }}
      Before={{ fetch_key_service_before }}

      [Service]
      Type=oneshot
      RemainAfterExit=true
      ExecStart=/usr/local/bin/open_volume "{{ key_server }}" {{ disk_image_path }} {{ device_name }}
      ExecStop=/usr/sbin/cryptsetup close {{ device_name }}

      [Install]
      WantedBy={{ fetch_key_service_wantedby }}

- name: Create service to mount the local filesystem
  become: true
  ansible.builtin.copy:
    dest: /etc/systemd/system/{{ mount_service }}
    mode: "0644"
    content: |
      [Unit]

      Description={{ item.name }} mount service
      After={{ key_fetch_service }}
      Requires={{ key_fetch_service }}
      Before={{ mount_service_before }}

      [Mount]
      What=/dev/mapper/{{ device_name }}
      Where={{ mount_point }}
      Type=ext4
      Options=defaults

      [Install]
      WantedBy={{ mount_service_wantedby }}

- name: Reload systemd daemon
  become: true
  ansible.builtin.systemd:
    daemon_reload: true

- name: Enable the services
  become: true
  ansible.builtin.systemd:
    name: "{{ item }}"
    enabled: true
  loop:
    - "{{ key_fetch_service }}"
    - "{{ mount_service }}"

- name: Start the services
  become: true
  ansible.builtin.systemd:
    name: "{{ item }}"
    state: started
  loop:
    - "{{ key_fetch_service }}"
    - "{{ mount_service }}"

- name: Mount the volume
  become: true
  ansible.posix.mount:
    path: "{{ mount_point }}"
    src: /dev/mapper/{{ device_name }}
    fstype: "{{ fstype }}"
    state: present
