---
- name: Set version specific variables
  include_tasks: tasks/set_vars.yml

- name: Ensure certificate role dependencies are installed
  package:
    name: "{{ __certificate_packages }}"
    state: present
    use: "{{ (__certificate_is_ostree | d(false)) |
      ternary('ansible.posix.rhel_rpm_ostree', omit) }}"

- name: Install and configure required providers
  vars:
    __certificate_providers: "{{ (certificate_requests | selectattr('provider', 'defined') | map(attribute='provider') | list) +
      [__certificate_provider_default] | unique | list }}"
  block:
    - name: Ensure provider packages are installed
      package:
        name: "{{ __certificate_provider_vars[__certificate_provider].packages }}"
        state: present
        use: "{{ (__certificate_is_ostree | d(false)) |
          ternary('ansible.posix.rhel_rpm_ostree', omit) }}"
      loop: "{{ __certificate_providers }}"
      loop_control:
        loop_var: __certificate_provider
      when: __certificate_provider_vars[__certificate_provider].packages is defined

    - name: Ensure pre-scripts hooks directory exists
      file:
        name: >-
          {{ __certificate_provider_vars[
            __certificate_provider
          ].config_dir }}/pre-scripts
        owner: >-
          {{ __certificate_provider_vars[
            __certificate_provider
          ].hooks_dirs_owner }}
        group: >-
          {{ __certificate_provider_vars[
            __certificate_provider
          ].hooks_dirs_group }}
        mode: >-
          {{ __certificate_provider_vars[
            __certificate_provider
          ].hooks_dirs_mode }}
        state: directory
      loop: "{{ __certificate_providers }}"
      loop_control:
        loop_var: __certificate_provider
      when: __certificate_provider_vars[__certificate_provider].config_dir is defined

    - name: Ensure post-scripts hooks directory exists
      file:
        name: >-
          {{ __certificate_provider_vars[
            __certificate_provider
          ].config_dir }}/post-scripts
        owner: >-
          {{ __certificate_provider_vars[
            __certificate_provider
          ].hooks_dirs_owner }}
        group: >-
          {{ __certificate_provider_vars[
            __certificate_provider
          ].hooks_dirs_group }}
        mode: >-
          {{ __certificate_provider_vars[
            __certificate_provider
          ].hooks_dirs_mode }}
        state: directory
      loop: "{{ __certificate_providers }}"
      loop_control:
        loop_var: __certificate_provider
      when: __certificate_provider_vars[__certificate_provider].config_dir is defined

    # While most Linux system roles have a list of services
    #   this role doesn't need it. In fact some providers
    #   won't have any service at all.
    - name: Ensure provider service is running
      service:
        name: "{{ __certificate_provider_vars[__certificate_provider].service }}"
        state: "{{ 'started' if __certificate_is_booted else omit }}"
        enabled: true
      loop: "{{ __certificate_providers }}"
      loop_control:
        loop_var: __certificate_provider
      when: __certificate_provider_vars[__certificate_provider].service is defined

- name: Ensure certificate requests
  certificate_request:
    name: "{{ item.name | default(omit) }}"
    dns: "{{ item.dns | default(omit) }}"
    ip: "{{ item.ip | default(omit) }}"
    email: "{{ item.email | default(omit) }}"
    common_name: "{{ item.common_name | default(omit) }}"
    owner: "{{ item.owner | default(omit) }}"
    group: "{{ item.group | default(omit) }}"
    mode: "{{ item.mode | default(omit) }}"
    provider: "{{ item.provider | default(omit) }}"
    principal: "{{ item.principal | default(omit) }}"
    directory: "{{ __certificate_default_directory }}"
    provider_config_directory: >-
      {{ __certificate_provider_vars[item.provider].config_dir
         if item.provider is defined
           and item.provider in __certificate_provider_vars
         else omit }}
    key_size: "{{ item.key_size | default(omit) }}"
    key_usage: "{{ item.key_usage | default(omit) }}"
    extended_key_usage: "{{ item.extended_key_usage | default(omit) }}"
    auto_renew: "{{ item.auto_renew | default(omit) }}"
    wait: "{{ certificate_wait }}"
    country: "{{ item.country | default(omit) }}"
    state: "{{ item.state | default(omit) }}"
    locality: "{{ item.locality | default(omit) }}"
    organization: "{{ item.organization | default(omit) }}"
    organizational_unit: "{{ item.organizational_unit | default(omit) }}"
    contact_email: "{{ item.contact_email | default(omit) }}"
    run_before: "{{ item.run_before | default(omit) }}"
    run_after: "{{ item.run_after | default(omit) }}"
    ca: "{{ item.ca | default(omit) }}"
    __header: "{{ __lsr_ansible_managed }}"
    booted: "{{ __certificate_is_booted }}"
  loop: "{{ certificate_requests }}"
  vars:
    __lsr_ansible_managed: "{{
      lookup('template', 'get_ansible_managed.j2') }}"

# For using this role to issue certs for tests for other
# system roles.  Assumes that the calling role wants
# self signed certs e.g. as a replacement for various
# openssl calls to generate certs, keys.  Also assumes
# that each item in certificate_requests has a unique
# name that can be used as the keys to the
# certificate_test_certs dict
- name: Handle test mode
  when: certificate_test_mode | d(false)
  vars:
    __cert_dir: "{{ __certificate_default_directory ~ '/certs' }}"
    __key_dir: "{{ __certificate_default_directory ~ '/private' }}"
    __ca_dir: "{{ __certificate_default_directory ~ '/certs' }}"
  block:
    - name: Check if test mode is supported
      fail:
        msg: "Test mode is not supported in non-booted mode."
      when: not __certificate_is_booted

    - name: Slurp the contents of the files
      slurp:
        path: "{{ __file }}"
      register: __certificate_test_data
      loop: "{{ ['cert', 'key', 'ca'] | product(certificate_requests) | list }}"
      vars:
        __file: "{{ __cert_dir ~ '/' ~ item[1].name ~ '.crt'
          if item[0] == 'cert' else
          __key_dir ~ '/' ~ item[1].name ~ '.key'
          if item[0] == 'key' else
          __ca_dir ~ '/' ~ item[1].name ~ '.crt' }}"

    - name: Reset certificate_test_certs
      set_fact:
        certificate_test_certs: {}

    - name: Create return data
      set_fact:
        certificate_test_certs: "{{ certificate_test_certs | combine({cert_name: cert_data}) }}"
      loop: "{{ __certificate_test_data.results | map(attribute='item.1.name') | unique | list }}"
      loop_control:
        loop_var: cert_name
      vars:
        name_match: "{{ '^' ~ cert_name ~ '$' }}"
        cert_data: "{{ dict((file_keys + content_keys) | zip(file_vals + content_vals)) }}"
        file_keys: "{{ __certificate_test_data.results | selectattr('item.1.name', 'match', name_match) |
          map(attribute='item.0') | list }}"
        content_keys: "{{ file_keys | map('regex_replace', '$', '_content') | list }}"
        file_vals: "{{ __certificate_test_data.results | selectattr('item.1.name', 'match', name_match) |
          map(attribute='source') | list }}"
        content_vals: "{{ __certificate_test_data.results | selectattr('item.1.name', 'match', name_match) |
          map(attribute='content') | map('b64decode') | list }}"

    - name: Stop tracking certificates
      command: getcert stop-tracking -f {{ item.cert }}
      changed_when: false
      loop: "{{ certificate_test_certs.values() | list }}"

    - name: Remove files
      file:
        path: "{{ item }}"
        state: absent
      when: certificate_test_remove_files | d(false)
      loop: "{{ __certs + __keys + __ca }}"
      vars:
        __certs: "{{ certificate_test_certs.values() | map(attribute='cert') |
          list }}"
        __keys: "{{ certificate_test_certs.values() | map(attribute='key') |
          list }}"
        __ca: "{{ certificate_test_certs.values() | map(attribute='ca') |
          list }}"
