--- # ============================================================================ # preflight-homarr.yml — reachability pre-flight for Homarr (NO host changes) # ============================================================================ # Read-only gate. Confirms, in order: # 1. Infisical auth + deploy SSH key retrievable (runner). # 2. Target host reachable over SSH as the `ansible` user. # 3. Rootless docker is usable (docker version). # 4. The `homarr` container exists and is running. # 5. Homarr answers HTTP on its port. # Fails with a clear reason at the first broken link. Changes nothing on the host. # # Run this before update-homarr-checked.yml, or any time to confirm Homarr health. # # Connects AS the `ansible` user via the Infisical-injected deploy key (same # pattern as deploy-homarr.yml / update-homarr.yml). # # Usage: playbook playbooks/preflight-homarr.yml, extra vars: target=racknerd1 # ============================================================================ - name: "PRECHECK — fetch deploy SSH key from Infisical" hosts: localhost gather_facts: false vars: infisical_url: "{{ lookup('env','INFISICAL_URL') | default('http://192.168.122.41:8080', true) }}" infisical_env_slug: "{{ lookup('env','INFISICAL_ENV_SLUG') | default('dev', true) }}" tasks: - name: "[precheck] Infisical auth vars present?" ansible.builtin.assert: that: - lookup('env','INFISICAL_CLIENT_ID') | length > 0 - lookup('env','INFISICAL_CLIENT_SECRET') | length > 0 - lookup('env','INFISICAL_PROJECT_ID') | length > 0 fail_msg: "Missing INFISICAL_CLIENT_ID / _SECRET / _PROJECT_ID in Semaphore Environment." - name: "[precheck] Login to Infisical" infisical.vault.login: url: "{{ infisical_url }}" auth_method: universal_auth universal_auth_client_id: "{{ lookup('env','INFISICAL_CLIENT_ID') }}" universal_auth_client_secret: "{{ lookup('env','INFISICAL_CLIENT_SECRET') }}" register: infisical_login - name: "[precheck] Read secrets" infisical.vault.read_secrets: login_data: "{{ infisical_login.login_data }}" project_id: "{{ lookup('env','INFISICAL_PROJECT_ID') }}" env_slug: "{{ infisical_env_slug }}" path: "/" as_dict: true register: infisical_secrets - name: "[precheck] stash SSH key for preflight play" ansible.builtin.set_fact: pc_ssh_privkey: "{{ infisical_secrets.secrets.SSH_PRIVATE_KEY }}" no_log: true - name: "[precheck] write deploy private key to runner temp (0600)" ansible.builtin.copy: dest: "/tmp/homarr_deploy_key" content: "{{ pc_ssh_privkey }}\n" mode: "0600" no_log: true - name: "PRE-FLIGHT — reachability + Homarr health (read-only)" hosts: "{{ target | default('racknerd1') }}" gather_facts: false vars: deploy_user: ansible homarr_dir: "/home/{{ deploy_user }}/docker/homarr" homarr_port: 7575 ansible_user: ansible ansible_ssh_private_key_file: "/tmp/homarr_deploy_key" ansible_ssh_common_args: "-o StrictHostKeyChecking=accept-new -o IdentitiesOnly=yes" tasks: - name: "[1/5] SSH reachable as ansible user?" ansible.builtin.ping: - name: Reset connection so docker group membership is active in this session ansible.builtin.meta: reset_connection - name: "[2/5] Rootless docker usable?" ansible.builtin.command: docker version register: dv changed_when: false failed_when: dv.rc != 0 - name: "[3/5] Homarr container present + running?" ansible.builtin.command: cmd: docker inspect --format '{{ '{{' }}.State.Running{{ '}}' }}' homarr register: homarr_state changed_when: false failed_when: false - name: "Assert homarr container is running" ansible.builtin.assert: that: - homarr_state.rc == 0 - homarr_state.stdout | trim == 'true' fail_msg: >- Homarr container is not running on {{ inventory_hostname }} (docker inspect rc={{ homarr_state.rc }}, state='{{ homarr_state.stdout | trim }}'). Run deploy-homarr.yml. - name: "[4/5] Compose stack file present?" ansible.builtin.stat: path: "{{ homarr_dir }}/docker-compose.yml" register: compose_file - name: "Warn if compose file missing (container running without repo compose)" ansible.builtin.debug: msg: >- NOTE: no docker-compose.yml at {{ homarr_dir }} — container is running but update-homarr-checked.yml expects the compose stack. Deploy first if updating. when: not compose_file.stat.exists - name: "[5/5] Homarr answers HTTP?" ansible.builtin.uri: url: "http://127.0.0.1:{{ homarr_port }}/" status_code: [200, 302, 307] register: health retries: 6 delay: 5 until: health.status is defined and health.status in [200, 302, 307] - name: "PRE-FLIGHT PASSED" ansible.builtin.debug: msg: >- Homarr reachable on {{ inventory_hostname }}:{{ homarr_port }} (HTTP {{ health.status }}) — safe to update. - name: "Cleanup runner temp key" hosts: localhost gather_facts: false tasks: - name: "remove temp deploy key from runner" ansible.builtin.file: path: /tmp/homarr_deploy_key state: absent