05_proxy_wiring.ymlΒΆ

---
# The unit is RemainAfterExit=yes, so success is 'active'; 'inactive' must NOT count as
# terminal (it is also the queued-not-yet-started state behind After=docker.service, and
# it is where the unit STAYS when its docker.service dependency fails - hence the
# docker= probe, without which a dead inner daemon burns the whole wait budget).
# ActiveState matched via stdout_lines: 'ActiveState=active' is a substring of 'ActiveState=activating'.
- name: "πŸ” ansible-flavor: rerun a matrix-mdad bootstrap a prior deploy left failed"
  ansible.builtin.shell:
    cmd: >-
      container exec {{ MATRIX_MDAD_CONTAINER_ADDRESS }}
      sh -c 'systemctl is-failed --quiet matrix-mdad-bootstrap.service || exit 0;
      systemctl reset-failed matrix-mdad-bootstrap.service;
      systemctl start --no-block matrix-mdad-bootstrap.service;
      echo restarted'
  register: matrix_mdad_bootstrap_rerun
  changed_when: "'restarted' in matrix_mdad_bootstrap_rerun.stdout"

- name: "⏳ ansible-flavor: await matrix-mdad bootstrap oneshot (cold ~10-15min)"
  ansible.builtin.shell:
    cmd: >-
      container exec {{ MATRIX_MDAD_CONTAINER_ADDRESS }}
      sh -c 'systemctl show -p LoadState,ActiveState matrix-mdad-bootstrap.service;
      printf "docker=%s\n" "$(systemctl is-failed docker.service)"'
  register: matrix_mdad_bootstrap_state
  retries: 360
  delay: 5
  until: >-
    'docker=failed' in matrix_mdad_bootstrap_state.stdout_lines | default([])
    or (
      'LoadState=loaded' in matrix_mdad_bootstrap_state.stdout_lines | default([])
      and (
        'ActiveState=failed' in matrix_mdad_bootstrap_state.stdout_lines | default([])
        or 'ActiveState=active' in matrix_mdad_bootstrap_state.stdout_lines | default([])
      )
    )
  changed_when: false
  ignore_errors: true

- name: "πŸ” ansible-flavor: probe Synapse client API on loopback"
  uri_retry:
    url: "http://127.0.0.1:{{ MATRIX_SYNAPSE_PORT }}/_matrix/client/versions"
    status_code: 200
    follow_redirects: none
  register: matrix_synapse_loopback_probe
  retries: 60
  delay: 5
  until: matrix_synapse_loopback_probe.status == 200
  ignore_errors: true
  when:
    - matrix_mdad_bootstrap_state is succeeded
    - "'ActiveState=failed' not in matrix_mdad_bootstrap_state.stdout_lines | default([])"
    - "'docker=failed' not in matrix_mdad_bootstrap_state.stdout_lines | default([])"

- name: "πŸ› ansible-flavor: matrix-mdad container/systemd/bootstrap status on failure"
  ansible.builtin.script:
    cmd: "{{ role_path }}/files/flavor/ansible/diagnostics.sh"
  environment:
    MATRIX_CONTAINER: "{{ MATRIX_MDAD_CONTAINER }}"
  register: matrix_mdad_diagnostics
  changed_when: false
  failed_when: false
  when: >-
    matrix_mdad_bootstrap_state is failed
    or 'ActiveState=failed' in matrix_mdad_bootstrap_state.stdout_lines | default([])
    or 'docker=failed' in matrix_mdad_bootstrap_state.stdout_lines | default([])
    or (matrix_synapse_loopback_probe is not skipped and matrix_synapse_loopback_probe is failed)

- name: "πŸ›‘ ansible-flavor: report the matrix-mdad diagnostics and fail"
  when: matrix_mdad_diagnostics is not skipped
  block:
    - name: "πŸ’Ύ ansible-flavor: dump matrix-mdad diagnostics"
      ansible.builtin.debug:
        var: matrix_mdad_diagnostics

    - name: "πŸ›‘ ansible-flavor: fail after diagnostics if Synapse never became reachable"
      ansible.builtin.fail:
        msg: >-
          {% if 'docker=failed' in matrix_mdad_bootstrap_state.stdout_lines | default([]) -%}
          the docker daemon inside matrix-mdad failed to start - see matrix_mdad_diagnostics above.
          {%- elif 'ActiveState=failed' in matrix_mdad_bootstrap_state.stdout_lines | default([]) -%}
          matrix-mdad bootstrap failed inside the container, in its galaxy install or its playbook - see matrix_mdad_diagnostics above.
          {%- elif matrix_mdad_bootstrap_state is failed -%}
          matrix-mdad bootstrap never reached a terminal state within the wait budget - see matrix_mdad_diagnostics above.
          {%- else -%}
          Synapse loopback probe never reached 200 - see matrix_mdad_diagnostics above.
          {%- endif %}

- name: "πŸ” ansible-flavor: probe Element web client on host loopback"
  uri_retry:
    url: "http://127.0.0.1:{{ MATRIX_ELEMENT_PORT }}/"
    status_code: 200
    follow_redirects: none
  register: matrix_element_loopback_probe
  retries: 30
  delay: 2
  until: matrix_element_loopback_probe.status == 200

- name: "πŸ”‘ ansible-flavor: converge the native Synapse admin account"
  when: IS_STACK_HOST | bool
  block:
    - name: "πŸ“ ansible-flavor: create native Synapse admin (DiD, idempotent shared-secret)"
      ansible.builtin.shell:
        cmd: >- # nocheck: raw-docker, container-exec-resolver, container-address-quote  inner docker CLI talks to the DiD daemon inside matrix-mdad; no host docker involved; ansible flavor forces compose mode
          container exec -e MATRIX_ADMINISTRATOR_PASSWORD {{ MATRIX_MDAD_CONTAINER_ADDRESS | quote }} sh -lc 'docker exec matrix-synapse register_new_matrix_user
          -u "{{ MATRIX_ADMINISTRATOR_USERNAME }}"
          -p "$MATRIX_ADMINISTRATOR_PASSWORD"
          -a -c {{ lookup('volume', 'web-app-matrix', 'synapse_config').target }} http://localhost:8008'
      environment:
        MATRIX_ADMINISTRATOR_PASSWORD: "{{ MATRIX_ADMINISTRATOR_PASSWORD }}"
      register: matrix_admin_create
      changed_when: matrix_admin_create.rc == 0 and 'User ID already taken' not in (matrix_admin_create.stdout + matrix_admin_create.stderr)
      failed_when: matrix_admin_create.rc != 0 and 'User ID already taken' not in (matrix_admin_create.stdout + matrix_admin_create.stderr)
      no_log: "{{ MASK_CREDENTIALS_IN_LOGS | bool }}"

    - name: "πŸ”‘ ansible-flavor: realign the admin password Synapse stored"
      when: not matrix_admin_create.changed
      no_log: "{{ MASK_CREDENTIALS_IN_LOGS | bool }}"
      block:
        - name: "πŸ”‘ ansible-flavor: hash the declared admin password"
          ansible.builtin.shell:
            cmd: >- # nocheck: raw-docker, container-exec-resolver  inner docker CLI talks to the DiD daemon inside matrix-mdad; no host docker involved
              container exec -i {{ MATRIX_MDAD_CONTAINER_ADDRESS }} docker exec -i matrix-synapse
              hash_password -c {{ MATRIX_SYNAPSE_CONFIG_PATH_CONTAINER | quote }}
            stdin: "{{ MATRIX_ADMINISTRATOR_PASSWORD }}"
            executable: /bin/bash
          register: matrix_mdad_password_hash
          changed_when: false

        - name: "πŸ”‘ ansible-flavor: point the admin at the declared password"
          ansible.builtin.shell:
            cmd: >-
              container exec -i -e PGPASSWORD
              {{ lookup('database', application_id, 'address') }}
              psql -v ON_ERROR_STOP=1 -U {{ MATRIX_POSTGRES_USER | quote }}
              -d {{ MATRIX_POSTGRES_DATABASE | quote }}
              -v hash={{ (matrix_mdad_password_hash.stdout_lines | last | trim) | quote }}
              -v name={{ lookup('mxid', MATRIX_ADMINISTRATOR_USERNAME) | quote }}
              -f -
            stdin: "{{ lookup('file', 'sql/realign_user_password.sql') }}"
            executable: /bin/bash
          environment:
            PGPASSWORD: "{{ MATRIX_POSTGRES_PASSWORD }}"
          register: matrix_mdad_password_update
          changed_when: "'UPDATE 1' in matrix_mdad_password_update.stdout"
          failed_when: >-
            matrix_mdad_password_update.rc != 0
            or 'UPDATE 1' not in matrix_mdad_password_update.stdout

- name: "πŸ”‘ ansible-flavor: align the Jitsi component accounts with their passwords"
  when:
    - IS_STACK_HOST | bool
    - MATRIX_JITSI_INTERNAL | bool
  ansible.builtin.shell:
    cmd: >- # nocheck: raw-docker, container-exec-resolver, container-address-quote  inner docker CLI talks to the DiD daemon inside matrix-mdad; Prosody keeps an account's first password, so a rotated secret needs the account recreated
      container exec -i {{ MATRIX_MDAD_CONTAINER_ADDRESS | quote }} docker exec -i matrix-jitsi-prosody sh -c
      'IFS= read -r p; prosodyctl --config /run/prosody/config/prosody.cfg.lua deluser "$1@auth.meet.jitsi"
      && prosodyctl --config /run/prosody/config/prosody.cfg.lua register "$1" auth.meet.jitsi "$p"'
      _ {{ item.user | quote }}
    stdin: "{{ item.password }}"
  loop: "{{ MATRIX_JITSI_COMPONENT_ACCOUNTS }}"
  loop_control:
    label: "{{ item.user }}"
  register: matrix_jitsi_component_accounts
  retries: 12
  delay: 5
  until: matrix_jitsi_component_accounts.rc == 0
  changed_when: true
  no_log: "{{ MASK_CREDENTIALS_IN_LOGS | bool }}"

- name: "πŸ”€ front-proxy: Element web client"
  ansible.builtin.include_role:
    name: sys-stk-front-proxy
  vars:
    domain: "{{ MATRIX_ELEMENT_DOMAIN }}"
    http_port: "{{ MATRIX_ELEMENT_PORT }}"
    proxy_internal_port: 8080

- name: "πŸ”€ front-proxy: Synapse client/federation"
  ansible.builtin.include_role:
    name: sys-stk-front-proxy
  vars:
    domain: "{{ MATRIX_SYNAPSE_DOMAIN }}"
    http_port: "{{ MATRIX_SYNAPSE_PORT }}"
    proxy_internal_port: "{{ MATRIX_SYNAPSE_CONTAINER_PORT }}"

- name: "πŸ”€ front-proxy: federation delegation"
  ansible.builtin.include_tasks: "{{ role_path }}/tasks/utils/well_known.yml"

- name: "πŸ”€ front-proxy: Jitsi web"
  ansible.builtin.include_role:
    name: sys-stk-front-proxy
  vars:
    domain: "{{ MATRIX_JITSI_DOMAIN }}"
    http_port: "{{ MATRIX_JITSI_PORT }}"
    proxy_internal_port: "{{ MATRIX_JITSI_CONTAINER_PORT }}"
  when: MATRIX_JITSI_INTERNAL | bool