---
# Proxmox VE Management Playbook
# Inventory and health check for VMs, LXC containers, storage, and recent tasks
# Usage: ansible-playbook playbooks/proxmox_management.yml -i hosts.ini
# Usage: ansible-playbook playbooks/proxmox_management.yml -i hosts.ini -e action=snapshot -e vm_id=100

- name: Proxmox VE Management
  hosts: pve
  gather_facts: yes
  become: false

  vars:
    action: "{{ action | default('status') }}"
    vm_id: "{{ vm_id | default('') }}"
    report_dir: "/tmp/health_reports"

  tasks:

    # ---------- Report directory ----------
    - name: Ensure health report directory exists
      ansible.builtin.file:
        path: "{{ report_dir }}"
        state: directory
        mode: '0755'
      delegate_to: localhost
      run_once: true

    # ---------- Status mode ----------
    - name: Get PVE version
      ansible.builtin.command: pveversion
      register: pve_version
      changed_when: false
      failed_when: false
      when: action == 'status'

    - name: Get node resource summary
      ansible.builtin.shell: |
        pvesh get /nodes/$(hostname)/status --output-format json 2>/dev/null || \
          echo '{"error": "pvesh not available"}'
      register: node_status_raw
      changed_when: false
      failed_when: false
      when: action == 'status'

    - name: List all VMs
      ansible.builtin.command: qm list
      register: vm_list
      changed_when: false
      failed_when: false
      when: action == 'status'

    - name: List all LXC containers
      ansible.builtin.command: pct list
      register: lxc_list
      changed_when: false
      failed_when: false
      when: action == 'status'

    - name: Count running VMs
      ansible.builtin.shell: qm list 2>/dev/null | grep -c running || echo "0"
      register: running_vm_count
      changed_when: false
      failed_when: false
      when: action == 'status'

    - name: Count running LXC containers
      ansible.builtin.shell: pct list 2>/dev/null | grep -c running || echo "0"
      register: running_lxc_count
      changed_when: false
      failed_when: false
      when: action == 'status'

    - name: Get storage pool status
      ansible.builtin.shell: |
        pvesh get /nodes/$(hostname)/storage --output-format json 2>/dev/null | python3 << 'PYEOF' || pvesm status 2>/dev/null || echo "Storage info unavailable"
        import sys, json
        try:
            pools = json.load(sys.stdin)
        except Exception:
            sys.exit(1)
        print('{:<20} {:<15} {:>8} {:>14}'.format('Storage', 'Type', 'Used%', 'Avail (GiB)'))
        print('-' * 62)
        for p in pools:
            name      = p.get('storage', 'n/a')
            stype     = p.get('type', 'n/a')
            total     = p.get('total', 0)
            used      = p.get('used', 0)
            avail     = p.get('avail', 0)
            pct       = round(used / total * 100, 1) if total and total > 0 else 0.0
            avail_gib = round(avail / 1024**3, 2)
            print('{:<20} {:<15} {:>7}% {:>13} GiB'.format(name, stype, pct, avail_gib))
        PYEOF
      register: storage_status
      changed_when: false
      failed_when: false
      when: action == 'status'

    - name: Get last 10 task log entries
      ansible.builtin.shell: |
        pvesh get /nodes/$(hostname)/tasks --limit 10 --output-format json 2>/dev/null | python3 << 'PYEOF' || echo "Task log unavailable"
        import sys, json, datetime
        try:
            tasks = json.load(sys.stdin)
        except Exception:
            sys.exit(1)
        print('{:<22} {:<12} {}'.format('Timestamp', 'Status', 'UPID'))
        print('-' * 80)
        for t in tasks:
            upid      = t.get('upid', 'n/a')
            status    = t.get('status', 'n/a')
            starttime = t.get('starttime', 0)
            try:
                ts = datetime.datetime.fromtimestamp(starttime).strftime('%Y-%m-%d %H:%M:%S')
            except Exception:
                ts = str(starttime)
            print('{:<22} {:<12} {}'.format(ts, status, upid[:60]))
        PYEOF
      register: task_log
      changed_when: false
      failed_when: false
      when: action == 'status'

    # ---------- Status summary ----------
    - name: Display Proxmox status summary
      ansible.builtin.debug:
        msg: |
          ============================================================
          Proxmox VE Status — {{ inventory_hostname }}
          ============================================================
          PVE Version   : {{ pve_version.stdout | default('n/a') }}
          Running VMs   : {{ running_vm_count.stdout | default('0') | trim }}
          Running LXCs  : {{ running_lxc_count.stdout | default('0') | trim }}

          --- Node Resource Summary (JSON) ---
          {{ node_status_raw.stdout | default('{}') | from_json | to_nice_json if (node_status_raw.stdout | default('') | length > 0 and node_status_raw.stdout | default('') is search('{')) else node_status_raw.stdout | default('unavailable') }}

          --- VMs (qm list) ---
          {{ vm_list.stdout | default('none') }}

          --- LXC Containers (pct list) ---
          {{ lxc_list.stdout | default('none') }}

          --- Storage Pools ---
          {{ storage_status.stdout | default('unavailable') }}

          --- Recent Tasks (last 10) ---
          {{ task_log.stdout | default('unavailable') }}
          ============================================================
      when: action == 'status'

    # ---------- Write JSON report ----------
    - name: Write Proxmox health JSON report
      ansible.builtin.copy:
        content: "{{ report_data | to_nice_json }}"
        dest: "{{ report_dir }}/proxmox_{{ ansible_date_time.date }}.json"
      vars:
        report_data:
          timestamp: "{{ ansible_date_time.iso8601 }}"
          host: "{{ inventory_hostname }}"
          pve_version: "{{ pve_version.stdout | default('n/a') | trim }}"
          running_vms: "{{ running_vm_count.stdout | default('0') | trim }}"
          running_lxcs: "{{ running_lxc_count.stdout | default('0') | trim }}"
          vm_list: "{{ vm_list.stdout | default('') }}"
          lxc_list: "{{ lxc_list.stdout | default('') }}"
          storage_status: "{{ storage_status.stdout | default('') }}"
          task_log: "{{ task_log.stdout | default('') }}"
          node_status_raw: "{{ node_status_raw.stdout | default('') }}"
      delegate_to: localhost
      run_once: true
      changed_when: false
      when: action == 'status'

    # ---------- Snapshot mode ----------
    - name: Create VM snapshot
      ansible.builtin.shell: >
        qm snapshot {{ vm_id }} "ansible-snap-{{ ansible_date_time.epoch }}"
        --description "Ansible automated snapshot"
      register: snapshot_result
      changed_when: true
      failed_when: false
      when:
        - action == 'snapshot'
        - vm_id | string | length > 0

    - name: Display snapshot result
      ansible.builtin.debug:
        msg: |
          Snapshot created on {{ inventory_hostname }}
          VM ID : {{ vm_id }}
          Result:
          {{ (snapshot_result | default({})).stdout | default('') }}
          {{ (snapshot_result | default({})).stderr | default('') }}
      when:
        - action == 'snapshot'
        - vm_id | string | length > 0
