---
# Update Portainer Edge Agent across homelab hosts
#
# Usage:
#   ansible-playbook -i hosts.ini playbooks/update_portainer_agent.yml
#   ansible-playbook -i hosts.ini playbooks/update_portainer_agent.yml -e "agent_version=2.33.7"
#   ansible-playbook -i hosts.ini playbooks/update_portainer_agent.yml --limit vish-concord-nuc
#
# Notes:
#   - Reads EDGE_ID and EDGE_KEY from the running container — no secrets needed in vars
#   - Set docker_bin in host_vars to override the docker binary path per host
#   - For Synology (calypso): docker_bin includes sudo prefix since Ansible become
#     does not reliably escalate on DSM

- name: Update Portainer Edge Agent
  hosts: portainer_edge_agents
  gather_facts: false
  vars:
    agent_version: "2.33.7"
    agent_image: "portainer/agent:{{ agent_version }}"
    container_name: portainer_edge_agent

  tasks:
    - name: Check container exists
      shell: "{{ docker_bin | default('docker') }} inspect {{ container_name }} --format '{{ '{{' }}.Id{{ '}}' }}'"
      register: container_check
      changed_when: false
      failed_when: container_check.rc != 0

    - name: Get current image
      shell: "{{ docker_bin | default('docker') }} inspect {{ container_name }} --format '{{ '{{' }}.Config.Image{{ '}}' }}'"
      register: current_image
      changed_when: false

    - name: Get EDGE environment vars from running container
      shell: "{{ docker_bin | default('docker') }} inspect {{ container_name }} --format '{{ '{{' }}json .Config.Env{{ '}}' }}'"
      register: container_env
      changed_when: false

    - name: Parse EDGE_ID
      set_fact:
        edge_id: "{{ (container_env.stdout | from_json | select('match', 'EDGE_ID=.*') | list | first).split('=', 1)[1] }}"

    - name: Parse EDGE_KEY
      set_fact:
        edge_key: "{{ (container_env.stdout | from_json | select('match', 'EDGE_KEY=.*') | list | first).split('=', 1)[1] }}"

    - name: Pull new agent image
      shell: "{{ docker_bin | default('docker') }} pull {{ agent_image }}"
      register: pull_result
      changed_when: "'Status: Downloaded newer image' in pull_result.stdout"

    - name: Skip if already on target version
      debug:
        msg: "{{ inventory_hostname }}: already running {{ agent_image }}, skipping recreate"
      when: current_image.stdout == agent_image and not pull_result.changed

    - name: Stop old container
      shell: "{{ docker_bin | default('docker') }} stop {{ container_name }}"
      when: current_image.stdout != agent_image or pull_result.changed

    - name: Remove old container
      shell: "{{ docker_bin | default('docker') }} rm {{ container_name }}"
      when: current_image.stdout != agent_image or pull_result.changed

    - name: Start new container
      shell: >
        {{ docker_bin | default('docker') }} run -d
        --name {{ container_name }}
        --restart always
        -v /var/run/docker.sock:/var/run/docker.sock
        -v {{ docker_volumes_path | default('/var/lib/docker/volumes') }}:/var/lib/docker/volumes
        -v /:/host
        -v portainer_agent_data:/data
        -e EDGE=1
        -e EDGE_ID={{ edge_id }}
        -e EDGE_KEY={{ edge_key }}
        -e EDGE_INSECURE_POLL=1
        {{ agent_image }}
      when: current_image.stdout != agent_image or pull_result.changed

    - name: Wait for container to be running
      shell: "{{ docker_bin | default('docker') }} ps --filter 'name={{ container_name }}' --format '{{ '{{' }}.Status{{ '}}' }}'"
      register: container_status
      retries: 5
      delay: 3
      until: "'Up' in container_status.stdout"
      when: current_image.stdout != agent_image or pull_result.changed

    - name: Report result
      debug:
        msg: "{{ inventory_hostname }}: {{ current_image.stdout }} → {{ agent_image }} | {{ container_status.stdout | default('no change') }}"
