---
- name: Bootstrap remote ansible environment
  hosts: linux
  tags:
    - always
  tasks:
    - include_tasks: tasks/meta/bootstrap-remote-env.yaml


- name: Clean up old orechestration data
  hosts: cluster
  gather_facts: false
  tags:
    - cleanup
  vars_files:
    - vars/services.yaml
    - vars/access.yaml
  tasks:
    - name: Create compose storage directory
      become: true
      ansible.builtin.file:
        path: "{{ skylab_compose_dir }}"
        state: directory
        owner: "{{ ansible_user }}"
        group: "{{ skylab_group_admin.name }}"
        mode: 0770

    - name: Fetch existing compose files
      ansible.builtin.command:
        cmd: /usr/bin/ls {{ skylab_compose_dir }}
      changed_when: false
      register: _compose_contents_raw

    - name: Remove legacy compose files
      when: item.replace('.yaml', '') not in skylab_services
      ansible.builtin.file:
        path: "{{ skylab_compose_dir }}/{{ item }}"
        state: absent
      loop: "{{ _compose_contents_raw.stdout_lines }}"

    - name: Fetch existing stacks
      vars:
        ansible_python_interpreter: "{{ skylab_ansible_venv }}/bin/python"
      community.docker.docker_stack_info: {}
      register: _stack_info

    - name: Remove legacy stacks
      vars:
        ansible_python_interpreter: "{{ skylab_ansible_venv }}/bin/python"
      when: item.Orchestrator == 'Swarm' and item.Name not in skylab_services
      community.docker.docker_stack:
        name: "{{ item.Name }}"
        state: absent
      loop: "{{ _stack_info.results }}"
      loop_control:
        label: "{{ item.Name }}"

    - name: Fetch existing Nginx configs
      ansible.builtin.command:
        cmd: ls {{ local_datastore_mount }}/appdata/nginx/conf.d/
      changed_when: false
      register: _nginx_configs

    - name: Remove legacy nginx configs
      when: item.replace('.conf', '') not in skylab_services
      ansible.builtin.file:
        path: "{{ local_datastore_mount }}/appdata/nginx/conf.d/{{ item }}.conf"
        state: absent
      loop: "{{ _nginx_configs.stdout_lines }}"


- name: Deploy stack service{{ (' ' + service) if service is defined else 's' }}
  hosts: cluster
  gather_facts: false
  vars:
    local_datastore_mount: /mnt/datastore
  vars_files:
    - vars/access.yaml
    - vars/services.yaml
  tasks:
    - name: Validate user input
      when: service is defined
      ansible.builtin.assert:
        that:
          - service in skylab_services

    - name: Determine service stacks to deploy
      ansible.builtin.set_fact:
        _services: "{{ {service: skylab_services[service]} if service is defined else skylab_services }}"

    - name: Determine app account mapping
      vars:
        _service_accounts: {}
      when: item.service | default(false)
      ansible.builtin.set_fact:
        _service_accounts: "{{ _service_accounts | combine({item.name: item}) }}"
      loop: "{{ skylab_accounts }}"
      loop_control:
        label: "{{ item.name }}"

    - name: Create compose directory
      become: true
      ansible.builtin.file:
        path: "{{ skylab_compose_dir }}"
        state: directory
        owner: "{{ ansible_user }}"
        group: "{{ skylab_group_admin.name }}"
        mode: 0770

    - name: Install compose file
      vars:
        app: "{{ item.value }}"
        _app_account: "{{ _service_accounts[item.value.user] if item.value.user is defined else false }}"
      ansible.builtin.template:
        src: docker-compose/{{ item.key }}.yaml.j2
        dest: "{{ skylab_compose_dir }}/{{ item.key }}.yaml"
        owner: "{{ ansible_user }}"
        group: "{{ skylab_group_admin.name }}"
        mode: 0660
      loop: "{{ _services | dict2items }}"
      loop_control:
        label: "{{ item.key }}"

    - name: Create automation groups
      become: true
      when: item.value.user is defined
      ansible.builtin.group:
        name: "{{ item.value.user }}"
        gid: "{{ _service_accounts[item.value.user].uid }}"
        state: present
      loop: "{{ _services | dict2items }}"
      loop_control:
        label: "{{ item.key }}"

    - name: Create automation accounts
      become: true
      when: item.value.user is defined
      ansible.builtin.user:
        name: "{{ item.value.user }}"
        state: present
        uid: "{{ _service_accounts[item.value.user].uid }}"
        group: "{{ item.value.user }}"
        groups: "{{ [skylab_group_automation.name, skylab_group.name] }}"
        system: true
        generate_ssh_key: false
        password: "{{ _service_accounts[item.value.user].password }}"
      loop: "{{ _services | dict2items }}"
      loop_control:
        label: "{{ item.key }}"

    - name: Configure datastore directories
      run_once: true
      block:
        - name: Determine volume directories
          vars:
            _stack_volume_directories: []
          when: item.value.volumes is defined
          ansible.builtin.set_fact:
            _stack_volume_directories: "{{ _stack_volume_directories + [{'user': (item.value.user | default(ansible_user)), 'volumes': (item.value.volumes.values() | list)}] }}"
          loop: "{{ _services | dict2items }}"
          loop_control:
            label: "{{ item.key }}"

        - name: Create service directories
          become: true
          ansible.builtin.file:
            path: "{{ local_datastore_mount }}{{ item.1 }}"
            state: directory
            owner: "{{ item.0.user }}"
            group: "{{ skylab_group_admin.name }}"
            mode: 0770
          loop: "{{ _stack_volume_directories | subelements('volumes') }}"

    - name: Deploy stack
      vars:
        ansible_python_interpreter: "{{ skylab_ansible_venv }}/bin/python"
      community.docker.docker_stack:
        name: "{{ item.key }}"
        compose:
          - "{{ skylab_compose_dir }}/{{ item.key }}.yaml"
        prune: false
        state: present
      loop: "{{ _services | dict2items }}"
      loop_control:
        label: "{{ item.key }}"

    - name: Configure reverse proxy
      run_once: true
      block:
        - name: Create nginx config
          when: item.value.domain is defined
          ansible.builtin.template:
            src: stack-nginx.conf.j2
            dest: "{{ local_datastore_mount }}/appdata/nginx/conf.d/{{ item.key }}.conf"
            owner: "{{ ansible_user }}"
            group: "{{ skylab_group_admin.name }}"
            mode: 0464
          loop: "{{ _services | dict2items }}"
          loop_control:
            label: "{{ item.value.domain | default(item.key) }}"
