#SPDX-License-Identifier: MIT-0
---
# tasks file for roles/init-vps
# @NOTE server deployment method is based on task tags compiled herein
- name: Informing user of requirement of two main domains 
  when: (certbot.domains | length) < 2 or (certbot.domains | length) > 2
  ansible.builtin.fail:
    msg: Only two domains allowed and required
- name: Informing user of requirement at least one wildcard
  when: (certbot.domains | select("regex", "^\\*\\.") | list | length) == 0
  ansible.builtin.fail:
    msg: At least one of the FQDNs must have a wildcard
# - name: Setting the FQDN for development
#   when: mode == "dev"
#   ansible.builtin.set_fact:
#     fqdn: "{{ (certbot.domains | map('regex_replace', '\\.([^\\.]*)$', '.test') | reject('regex', '^\\*\\.') | list)[0] }}"
- name: Setting the FQDN
  # when: mode == "prod"
  ansible.builtin.set_fact:
    fqdn: "{{ (certbot.domains | reject('regex', '^\\*\\.') | list)[0] }}"
- name: Finding SSH public keys for root
  delegate_facts: true
  delegate_to: localhost
  ansible.builtin.find:
    paths: "{{ local_facts['user_dir'] | default(lookup('env', 'HOME')) }}/.ssh" # @TODO define 'cnode_homedir' in playbook
    patterns: "{{ ['^'] | product(ssh_keys) | map('join') | list }}"
    file_type: file
    use_regex: true
  register: ssh_keypairs
- name: Reducing SSH key-pair results to list of SSH public key paths
  ansible.builtin.set_fact:
    root_pubkey_paths: "{{ ssh_keypairs.files | selectattr('path', 'search', '\\.pub$') | map(attribute='path') | list }}"
- name: Converting SSH public key paths to their file contents
  ansible.builtin.set_fact:
    root_pubkeys: "{{ root_pubkeys | default([]) + [lookup('file', item)] }}"
  loop: "{{ root_pubkey_paths }}"
- name: Ensuring password is defined for root user
  when: prehashed_password is undefined or prehashed_password == None
  block:
    - name: Prompting for password for or of root user
      when: password is undefined or password == None
      ansible.builtin.pause:
        prompt: "Provide a password for the root user"
        echo: false
      register: prompted_password
    - name: Getting the inputted password for root user
      when: prompted_password is defined or prompted_password != None
      ansible.builtin.set_fact:
        prehashed_password: "{{ prompted_password.user_input }}"
- name: Bootstrapping VPS
  block:
    - name: Ensuring token is available for VPS service API
      when: token is undefined or token == None
      ansible.builtin.pause:
        prompt: "Provide the API token for the given VPS service"
        echo: false
      register: prompted_token
    - name: Creating VPS via Linode VPS service API
      block:
        - name: Creating the VPS
          linode.cloud.instance:
            api_token: "{{ token | prompted_token.user_input }}"
            label: "{{ fqdn }}"
            type: g6-standard-2
            image: "{{ operating_system }}"
            disk_encryption: enabled
            region: "{{ origin }}"
            private_ip: true
            # @TODO find out if 'root_pass' attribute takes in hashed or plaintext password
            # root_pass: "{{ password | default((prehashed_password | lookup('password_hash', hashtype='sha512'))) }}" # IF HASHED
            root_pass: "{{ password | default(prehashed_password) }}" # IF PLAINTEXT
            authorized_keys: "{{ root_pubkeys }}"
            state: present
          register: new_instance
        - name: Waiting for that VPS to come online
          delegate_to: "{{ item }}"
          delegate_facts: true
          ansible.builtin.wait_for_connection:
            delay: 20
            timeout: 300
          vars:
            ansible_ssh_private_key_file: "{{ chosen_privkey | default(ssh_keypairs.files | rejectattr('path', 'search', '\\.pub$') | map(attribute='path') | list | random) }}" # @TODO define 'chosen_privkey'in playbook
          loop: "{{ new_instance.instance[ip_pref] }}"
      tags:
        - linode
  tags:
    - vps
- name: Bootstrapping homeserver
  block:
    - name: Installing operating system or distro in server 
      when: operating_system != None
      block:
        - name: Creating a server
          block: []
          tags:
            - unimplemented
        - name: Waiting for that server to come online
          delegate_to: "{{ item }}"
          delegate_facts: true
          remote_user: root
          when: item is ansible.utils['ip_pref']
          ansible.builtin.wait_for_connection:
            delay: 20
            timeout: 300
          loop: "{{ groups[fqdn] | default(hostvars[fqdn]) }}"
        - name: Checking if that server has required operating system
          delegate_to: "{{ item }}"
          delegate_facts: true
          remote_user: root
          when: ansible_facts["system"] != "Linux" and item is ansible.utils['ip_pref']
          ansible.builtin.fail:
            msg: Unsupported operating system found
          loop: "{{ groups[fqdn] | default(hostvars[fqdn]) }}"
        - name: Checking if that server has required Linux distro
          delegate_to: "{{ item }}"
          delegate_facts: true
          remote_user: root
          when: ansible_facts["system"] == "Linux" and ansible_facts["os_family"] != "Debian" and item is ansible.utils['ip_pref']
          ansible.builtin.fail:
            msg: Unsupported Linux distro found
          loop: "{{ groups[fqdn] | default(hostvars[fqdn]) }}"
    - name: Providing authorized keys for server root account
      delegate_to: "{{ item[0] }}"
      delegate_facts: true
      become: true
      remote_user: root
      ansible.posix.authorized_key:
        user: "{{ ansible_user }}"
        key: "{{ lookup('file', item[1]) }}"
        state: present
      loop: "{{ (groups[fqdn] | default(hostvars[fqdn])) | product(root_pubkey_paths) }}"
  tags:
    - lan
