---
- name: Append subdomains to hosts
  tags: hosts
  become: yes
  ansible.builtin.lineinfile:
    path: /etc/hosts
    backrefs: yes
    regexp: '^(127\.0\.1\.1 .*)$'
    line: "\\1 {{ api }} {{ mesh }} {{ rmm }}"

- name: set mouse mode for vim
  tags: vim
  become: yes
  ansible.builtin.copy:
    src: vimrc.local
    dest: /etc/vim/vimrc.local
    owner: "root"
    group: "root"
    mode: "0644"

- name: set max_user_watches
  tags: sysctl
  become: yes
  ansible.builtin.lineinfile:
    path: /etc/sysctl.conf
    line: fs.inotify.max_user_watches=524288

- name: reload sysctl
  tags: sysctl
  become: yes
  ansible.builtin.command:
    cmd: sysctl -p

- name: install base packages
  tags: base
  become: yes
  ansible.builtin.apt:
    pkg: "{{ item }}"
    state: present
    update_cache: yes
  with_items:
    - "{{ base_pkgs }}"

- name: set arch fact
  ansible.builtin.set_fact:
    goarch: "{{ 'amd64' if ansible_architecture == 'x86_64' else 'arm64' }}"

- name: download and install golang
  tags: golang
  become: yes
  ansible.builtin.unarchive:
    src: "https://go.dev/dl/go{{ go_ver }}.linux-{{ goarch }}.tar.gz"
    dest: /usr/local
    remote_src: yes

- name: add golang to path
  become: yes
  tags: golang
  ansible.builtin.copy:
    dest: /etc/profile.d/golang.sh
    content: "PATH=$PATH:/usr/local/go/bin"

- name: install python prereqs
  tags: python
  become: yes
  ansible.builtin.apt:
    pkg: "{{ item }}"
    state: present
  with_items:
    - "{{ python_pkgs }}"

- name: get cpu core count
  tags: python
  ansible.builtin.command: nproc
  register: numprocs

- name: Create python tmpdir
  tags: python
  ansible.builtin.tempfile:
    state: directory
    suffix: python
  register: python_tmp

- name: download and extract python
  tags: python
  ansible.builtin.unarchive:
    src: "https://www.python.org/ftp/python/{{ python_ver }}/Python-{{ python_ver }}.tgz"
    dest: "{{ python_tmp.path }}"
    remote_src: yes

- name: compile python
  tags: python
  ansible.builtin.shell:
    chdir: "{{ python_tmp.path }}/Python-{{ python_ver }}"
    cmd: |
      ./configure --enable-optimizations
      make -j {{ numprocs.stdout }}

- name: alt install python
  tags: python
  become: yes
  ansible.builtin.shell:
    chdir: "{{ python_tmp.path }}/Python-{{ python_ver }}"
    cmd: |
      make altinstall

- name: install redis
  tags: redis
  become: yes
  ansible.builtin.apt:
    pkg: redis
    state: present

- name: create postgres repo
  tags: postgres
  become: yes
  ansible.builtin.copy:
    content: "deb http://apt.postgresql.org/pub/repos/apt {{ ansible_distribution_release }}-pgdg main"
    dest: /etc/apt/sources.list.d/pgdg.list
    owner: root
    group: root
    mode: "0644"

- name: import postgres repo signing key
  tags: postgres
  become: yes
  ansible.builtin.apt_key:
    url: https://www.postgresql.org/media/keys/ACCC4CF8.asc
    state: present

- name: install postgresql
  tags: postgres
  become: yes
  ansible.builtin.apt:
    pkg: postgresql-15
    state: present
    update_cache: yes

- name: ensure postgres enabled and started
  tags: postgres
  become: yes
  ansible.builtin.service:
    name: postgresql
    enabled: yes
    state: started

- name: setup trmm database
  tags: postgres
  become: yes
  become_user: postgres
  ansible.builtin.shell:
    cmd: |
      psql -c "CREATE DATABASE tacticalrmm"
      psql -c "CREATE USER {{ db_user }} WITH PASSWORD '{{ db_passwd }}'"
      psql -c "ALTER ROLE {{ db_user }} SET client_encoding TO 'utf8'"
      psql -c "ALTER ROLE {{ db_user }} SET default_transaction_isolation TO 'read committed'"
      psql -c "ALTER ROLE {{ db_user }} SET timezone TO 'UTC'"
      psql -c "ALTER ROLE {{ db_user }} CREATEDB"
      psql -c "GRANT ALL PRIVILEGES ON DATABASE tacticalrmm TO {{ db_user }}"
      psql -c "ALTER DATABASE tacticalrmm OWNER TO {{ db_user }}"
      psql -c "GRANT USAGE, CREATE ON SCHEMA PUBLIC TO {{ db_user }}"

- name: setup mesh database
  tags: postgres
  become: yes
  become_user: postgres
  ansible.builtin.shell:
    cmd: |
      psql -c "CREATE DATABASE meshcentral"
      psql -c "CREATE USER {{ mesh_db_user }} WITH PASSWORD '{{ mesh_db_passwd }}'"
      psql -c "ALTER ROLE {{ mesh_db_user }} SET client_encoding TO 'utf8'"
      psql -c "ALTER ROLE {{ mesh_db_user }} SET default_transaction_isolation TO 'read committed'"
      psql -c "ALTER ROLE {{ mesh_db_user }} SET timezone TO 'UTC'"
      psql -c "GRANT ALL PRIVILEGES ON DATABASE meshcentral TO {{ mesh_db_user }}"
      psql -c "ALTER DATABASE meshcentral OWNER TO {{ mesh_db_user }}"
      psql -c "GRANT USAGE, CREATE ON SCHEMA PUBLIC TO {{ mesh_db_user }}"

- name: create repo dirs
  become: yes
  tags: git
  ansible.builtin.file:
    path: "{{ item }}"
    state: directory
    owner: "{{ user }}"
    group: "{{ user }}"
    mode: "0755"
  with_items:
    - "{{ backend_dir }}"
    - "{{ frontend_dir }}"
    - "{{ scripts_dir }}"

- name: git clone repos
  tags: git
  ansible.builtin.git:
    repo: "{{ item.repo }}"
    dest: "{{ item.dest }}"
    version: "{{ item.version }}"
  with_items:
    - {
        repo: "{{ backend_repo }}",
        dest: "{{ backend_dir }}",
        version: develop,
      }
    - {
        repo: "{{ frontend_repo }}",
        dest: "{{ frontend_dir }}",
        version: develop,
      }
    - { repo: "{{ scripts_repo }}", dest: "{{ scripts_dir }}", version: main }

- name: get nats_server_ver
  tags: nats
  ansible.builtin.shell: grep "^NATS_SERVER_VER" {{ settings_file }} | awk -F'[= "]' '{print $5}'
  register: nats_server_ver

- name: Create nats tmpdir
  tags: nats
  ansible.builtin.tempfile:
    state: directory
    suffix: nats
  register: nats_tmp

- name: download and extract nats
  tags: nats
  ansible.builtin.unarchive:
    src: "https://github.com/nats-io/nats-server/releases/download/v{{ nats_server_ver.stdout }}/nats-server-v{{ nats_server_ver.stdout }}-linux-{{ goarch }}.tar.gz"
    dest: "{{ nats_tmp.path }}"
    remote_src: yes

- name: install nats
  tags: nats
  become: yes
  ansible.builtin.copy:
    remote_src: yes
    src: "{{ nats_tmp.path }}/nats-server-v{{ nats_server_ver.stdout }}-linux-{{ goarch }}/nats-server"
    dest: /usr/local/bin/nats-server
    owner: "{{ user }}"
    group: "{{ user }}"
    mode: "0755"

- name: Create nodejs tmpdir
  tags: nodejs
  ansible.builtin.tempfile:
    state: directory
    suffix: nodejs
  register: nodejs_tmp

- name: download nodejs setup
  tags: nodejs
  ansible.builtin.get_url:
    url: https://deb.nodesource.com/setup_18.x
    dest: "{{ nodejs_tmp.path }}/setup_node.sh"
    mode: "0755"

- name: run node setup script
  tags: nodejs
  become: yes
  ansible.builtin.command:
    cmd: "{{ nodejs_tmp.path }}/setup_node.sh"

- name: install nodejs
  tags: nodejs
  become: yes
  ansible.builtin.apt:
    pkg: nodejs
    state: present
    update_cache: yes

- name: update npm
  tags: nodejs
  become: yes
  ansible.builtin.shell:
    cmd: npm install -g npm

- name: install quasar cli
  tags: quasar
  become: yes
  ansible.builtin.shell:
    cmd: npm install -g @quasar/cli

- name: install frontend
  tags: quasar
  ansible.builtin.shell:
    chdir: "{{ frontend_dir }}"
    cmd: npm install

- name: add quasar env
  tags: quasar
  ansible.builtin.template:
    src: quasar.env.j2
    dest: "{{ frontend_dir }}/.env"
    owner: "{{ user }}"
    group: "{{ user }}"
    mode: "0644"

- name: remove tempdirs
  tags: cleanup
  become: yes
  ignore_errors: yes
  ansible.builtin.file:
    path: "{{ item }}"
    state: absent
  with_items:
    - "{{ nats_tmp.path }}"
    - "{{ python_tmp.path }}"
    - "{{ nodejs_tmp.path }}"

- name: deploy fullchain
  tags: certs
  become: yes
  ansible.builtin.copy:
    src: "{{ fullchain_src }}"
    dest: "{{ fullchain_dest }}"
    owner: "{{ user }}"
    group: "{{ user }}"
    mode: "0440"

- name: deploy privkey
  tags: certs
  become: yes
  ansible.builtin.copy:
    src: "{{ privkey_src }}"
    dest: "{{ privkey_dest }}"
    owner: "{{ user }}"
    group: "{{ user }}"
    mode: "0440"

- name: import nginx signing key
  tags: nginx
  become: yes
  ansible.builtin.apt_key:
    url: https://nginx.org/keys/nginx_signing.key
    state: present

- name: add nginx repo
  tags: nginx
  become: yes
  ansible.builtin.template:
    src: nginx.repo.j2
    dest: /etc/apt/sources.list.d/nginx.list
    owner: "root"
    group: "root"
    mode: "0644"

- name: install nginx
  tags: nginx
  become: yes
  ansible.builtin.apt:
    pkg: nginx
    state: present
    update_cache: yes

- name: set nginx default conf
  tags: nginx
  become: yes
  ansible.builtin.copy:
    src: nginx-default.conf
    dest: /etc/nginx/nginx.conf
    owner: "root"
    group: "root"
    mode: "0644"

- name: create nginx dirs
  become: yes
  tags: nginx
  ansible.builtin.file:
    state: directory
    path: "{{ item }}"
    mode: "0755"
  with_items:
    - /etc/nginx/sites-available
    - /etc/nginx/sites-enabled

- name: deploy nginx sites
  become: yes
  tags: nginx
  ansible.builtin.template:
    src: "{{ item.src }}"
    dest: "{{ item.dest }}"
    mode: "0644"
    owner: root
    group: root
  with_items:
    - { src: backend.nginx.j2, dest: /etc/nginx/sites-available/backend.conf }
    - { src: mesh.nginx.j2, dest: /etc/nginx/sites-available/mesh.conf }

- name: enable nginx sites
  become: yes
  tags: nginx
  ansible.builtin.file:
    src: "{{ item.src }}"
    dest: "{{ item.dest }}"
    mode: "0644"
    owner: root
    group: root
    state: link
  with_items:
    - {
        src: /etc/nginx/sites-available/backend.conf,
        dest: /etc/nginx/sites-enabled/backend.conf,
      }
    - {
        src: /etc/nginx/sites-available/mesh.conf,
        dest: /etc/nginx/sites-enabled/mesh.conf,
      }

- name: ensure nginx enabled and restarted
  tags: nginx
  become: yes
  ansible.builtin.service:
    name: nginx
    enabled: yes
    state: restarted

- name: set natsapi fact
  ansible.builtin.set_fact:
    natsapi: "{{ 'nats-api' if ansible_architecture == 'x86_64' else 'nats-api-arm64' }}"

- name: copy nats-api bin
  tags: nats-api
  become: yes
  ansible.builtin.copy:
    remote_src: yes
    src: "{{ backend_dir }}/natsapi/bin/{{ natsapi }}"
    dest: /usr/local/bin/nats-api
    owner: "{{ user }}"
    group: "{{ user }}"
    mode: "0755"

- name: get setuptools_ver
  tags: pip
  ansible.builtin.shell: grep "^SETUPTOOLS_VER" {{ settings_file }} | awk -F'[= "]' '{print $5}'
  register: setuptools_ver

- name: get wheel_ver
  tags: pip
  ansible.builtin.shell: grep "^WHEEL_VER" {{ settings_file }} | awk -F'[= "]' '{print $5}'
  register: wheel_ver

- name: setup virtual env
  tags: pip
  ansible.builtin.shell:
    chdir: "{{ backend_dir }}/api"
    cmd: python3.11 -m venv env

- name: update pip to latest
  tags: pip
  ansible.builtin.pip:
    virtualenv: "{{ backend_dir }}/api/env"
    name: pip
    state: latest

- name: install setuptools and wheel
  tags: pip
  ansible.builtin.pip:
    virtualenv: "{{ backend_dir }}/api/env"
    name: "{{ item }}"
  with_items:
    - "setuptools=={{ setuptools_ver.stdout }}"
    - "wheel=={{ wheel_ver.stdout }}"

- name: install python packages
  tags: pip
  ansible.builtin.pip:
    virtualenv: "{{ backend_dir }}/api/env"
    chdir: "{{ backend_dir }}/api/tacticalrmm"
    requirements: "{{ item }}"
  with_items:
    - requirements.txt
    - requirements-dev.txt
    - requirements-test.txt

- name: deploy django local settings
  tags: django
  ansible.builtin.template:
    src: local_settings.j2
    dest: "{{ local_settings_file }}"
    mode: "0644"
    owner: "{{ user }}"
    group: "{{ user }}"

- name: setup django
  tags: django
  ansible.builtin.shell:
    chdir: "{{ backend_dir }}/api/tacticalrmm"
    cmd: |
      . ../env/bin/activate
      python manage.py migrate --no-input
      python manage.py collectstatic --no-input
      python manage.py create_natsapi_conf
      python manage.py load_chocos
      python manage.py load_community_scripts
      echo "from accounts.models import User; User.objects.create_superuser('{{ django_user }}', '{{ github_email }}', '{{ django_password }}') if not User.objects.filter(username='{{ django_user }}').exists() else 0;" | python manage.py shell
      python manage.py create_installer_user

- name: deploy services
  tags: services
  become: yes
  ansible.builtin.template:
    src: "{{ item.src }}"
    dest: "{{ item.dest }}"
    mode: "0644"
    owner: "root"
    group: "root"
  with_items:
    - { src: nats-api.systemd.j2, dest: /etc/systemd/system/nats-api.service }
    - { src: nats-server.systemd.j2, dest: /etc/systemd/system/nats.service }
    - { src: mesh.systemd.j2, dest: /etc/systemd/system/meshcentral.service }

- name: get mesh_ver
  tags: mesh
  ansible.builtin.shell: grep "^MESH_VER" {{ settings_file }} | awk -F'[= "]' '{print $5}'
  register: mesh_ver

- name: create meshcentral data directory
  tags: mesh
  become: yes
  ansible.builtin.file:
    path: "{{ mesh_dir }}/meshcentral-data"
    state: directory
    owner: "{{ user }}"
    group: "{{ user }}"
    mode: "0755"

- name: install meshcentral
  tags: mesh
  ansible.builtin.command:
    chdir: "{{ mesh_dir }}"
    cmd: "npm install meshcentral@{{ mesh_ver.stdout }}"

- name: deploy mesh config
  tags: mesh
  ansible.builtin.template:
    src: mesh.cfg.j2
    dest: "{{ mesh_dir }}/meshcentral-data/config.json"
    mode: "0644"
    owner: "{{ user }}"
    group: "{{ user }}"

- name: start meshcentral
  tags: mesh
  become: yes
  ansible.builtin.systemd:
    name: meshcentral.service
    state: started
    enabled: yes
    daemon_reload: yes

- name: wait for meshcentral to be ready
  tags: mesh
  uri:
    url: "https://{{ mesh }}"
    return_content: yes
    validate_certs: yes
    status_code: 200
  register: mesh_status
  until: mesh_status.status == 200
  retries: 20
  delay: 3

- name: get meshcentral login token key
  tags: mesh_key
  ansible.builtin.command:
    chdir: "{{ mesh_dir }}"
    cmd: node node_modules/meshcentral --logintokenkey
  register: mesh_token_key

- name: add mesh key to django settings file
  tags: mesh_key
  ansible.builtin.lineinfile:
    path: "{{ local_settings_file }}"
    line: 'MESH_TOKEN_KEY = "{{ mesh_token_key.stdout }}"'

- name: stop meshcentral service
  tags: mesh_user
  become: yes
  ansible.builtin.service:
    name: meshcentral.service
    state: stopped

- name: create mesh user
  tags: mesh_user
  ansible.builtin.shell:
    chdir: "{{ mesh_dir }}"
    cmd: |
      node node_modules/meshcentral --createaccount {{ mesh_user }} --pass {{ mesh_password }} --email {{ github_email }}
      node node_modules/meshcentral --adminaccount {{ mesh_user }}

- name: start meshcentral service
  tags: mesh_user
  become: yes
  ansible.builtin.service:
    name: meshcentral.service
    state: started

- name: wait for meshcentral to be ready
  tags: mesh_user
  uri:
    url: "https://{{ mesh }}"
    return_content: yes
    validate_certs: yes
    status_code: 200
  register: mesh_status
  until: mesh_status.status == 200
  retries: 20
  delay: 3

- name: create mesh device group
  tags: mesh_user
  ansible.builtin.shell:
    chdir: "{{ mesh_dir }}"
    cmd: |
      node node_modules/meshcentral/meshctrl.js --url wss://{{ mesh }}:443 --loginuser {{ mesh_user }} --loginpass {{ mesh_password }} AddDeviceGroup --name TacticalRMM

- name: finish up django
  tags: mesh_user
  ansible.builtin.shell:
    chdir: "{{ backend_dir }}/api/tacticalrmm"
    cmd: |
      . ../env/bin/activate
      python manage.py initial_db_setup
      python manage.py reload_nats

- name: restart services
  tags: services
  become: yes
  ansible.builtin.systemd:
    daemon_reload: yes
    enabled: yes
    state: restarted
    name: "{{ item }}.service"
  with_items:
    - nats
    - nats-api
