---
# Update bwvebox (production cluster) Proxmox LXC containers and VMs
# Usage: ansible-playbook -i inventory update-bwvebox.yml

- name: Update bwvebox Production LXC Containers and VMs
  hosts: bwvebox
  gather_facts: no
  vars:
    candidate_containers:
      # Critical services
      - 100   # supportme
      - 101   # matomo
      - 102   # snipeit
      - 103   # passbolt
      - 104   # INVESTBRAIN
      - 105   # visualdash
      # Infrastructure
      - 107   # netman
      - 108   # docuserv
      - 109   # dumanet
      - 110   # technitiumdns
      - 111   # minarca
      # AI & Data
      - 113   # BIGAI
      - 114   # grist
      - 115   # searxng
      - 116   # TWINGATE
      # Management
      - 117   # PORTAINER
      - 120   # netbox
      - 121   # RUSTDESK
      - 122   # odoocrm
      - 123   # nocodb
      - 124   # alpine-it-tools
      - 125   # pve-scripts-local
      - 126   # PPUSHER
      - 127   # UPTYME
      - 128   # KASM
      - 130   # excalidraw
      - 131   # beanalytics
      - 132   # bwitcloud
      - 136   # proxmox-datacenter-manager
      - 137   # pulse
      - 138   # beavault
      - 139   # patchman
      - 140   # mariadb
      - 141   # wordpress
      - 142   # bwitdnstoo
      - 143   # gitea
      - 145   # SPEED-TRACKER
      - 146   # apache-guacamole
      - 147   # BDAP
      - 148   # wireguard
      - 150   # N8NAI
      - 151   # POCKETID
      - 152   # myip
      - 153   # immich
      - 154   # web-check
      - 155   # rustfs
      - 156   # PROXMAN
      - 157   # KIMAI
      - 160   # postgresql
      - 161   # bentopdf
      - 164   # WHITEBOARD
      - 166   # DASHY
      - 168   # METABASE
      - 169   # INVOICE
      - 170   # HOMEASSISTANT
      - 171   # openobserve
      - 172   # vaultwarden
      - 173   # mail-archiver
    candidate_vms:
      - 112   # freepbx
      - 118   # BWINBOX
      - 133   # ollama-cpu
      - 134   # dockertemplate
      - 159   # POPUPOS
      - 9000  # ubuntu-24.04-cloud
      - 9001  # windows-server-2022
      - 9002  # debian-12-cloud
      - 9003  # debian-13-cloud

  tasks:
    - name: Discover running LXC containers
      ansible.builtin.shell:
        cmd: |
          for ct in {{ candidate_containers | join(' ') }}; do
            if sudo /usr/sbin/pct status "$ct" 2>/dev/null | grep -q running; then
              echo "$ct"
            fi
          done
      register: running_cts
      check_mode: no
      changed_when: false

    - name: Discover running VMs
      ansible.builtin.shell:
        cmd: |
          for vm in {{ candidate_vms | join(' ') }}; do
            if sudo /usr/sbin/qm status "$vm" 2>/dev/null | grep -q running; then
              echo "$vm"
            fi
          done
      register: running_vms
      check_mode: no
      changed_when: false

    - name: Detect OS in running containers
      ansible.builtin.shell:
        cmd: |
          CT_ID="{{ item }}"
          OS_INFO=$(sudo /usr/sbin/pct exec "$CT_ID" -- cat /etc/os-release 2>/dev/null || echo "")
          if echo "$OS_INFO" | grep -qi "alpine"; then echo "alpine"
          elif echo "$OS_INFO" | grep -qi "arch"; then echo "arch"
          elif echo "$OS_INFO" | grep -qi "debian"; then echo "debian"
          elif echo "$OS_INFO" | grep -qi "ubuntu"; then echo "ubuntu"
          elif echo "$OS_INFO" | grep -qi "devuan"; then echo "devuan"
          elif echo "$OS_INFO" | grep -qi "fedora"; then echo "fedora"
          elif echo "$OS_INFO" | grep -qi "rocky"; then echo "rocky"
          elif echo "$OS_INFO" | grep -qi "centos"; then echo "centos"
          elif echo "$OS_INFO" | grep -qi "alma"; then echo "alma"
          elif echo "$OS_INFO" | grep -qi "suse"; then echo "opensuse"
          else echo "unknown"
          fi
      loop: "{{ running_cts.stdout_lines }}"
      register: container_os
      check_mode: no
      changed_when: false
      when: running_cts.stdout_lines | length > 0

    - name: Update running containers with OS-specific package manager
      ansible.builtin.shell:
        cmd: |
          set -e
          CT_ID="{{ item[0] }}"
          OS_TYPE="{{ item[1] }}"
          
          echo "=== Updating container $CT_ID (OS: $OS_TYPE) ==="
          
          case "$OS_TYPE" in
            alpine)
              sudo /usr/sbin/pct exec "$CT_ID" -- sh -c 'apk update && apk upgrade -a'
              ;;
            arch)
              sudo /usr/sbin/pct exec "$CT_ID" -- bash -c 'pacman -Syyu --noconfirm'
              ;;
            fedora|rocky|centos|alma)
              sudo /usr/sbin/pct exec "$CT_ID" -- bash -c 'dnf -y update && dnf -y upgrade'
              ;;
            ubuntu|debian|devuan)
              sudo /usr/sbin/pct exec "$CT_ID" -- bash -c 'export DEBIAN_FRONTEND=noninteractive && apt-get update -qq && apt-get -yq dist-upgrade'
              ;;
            opensuse)
              sudo /usr/sbin/pct exec "$CT_ID" -- bash -c 'zypper ref && zypper --non-interactive dup'
              ;;
            *)
              echo "Unknown OS ($OS_TYPE), trying apt..."
              sudo /usr/sbin/pct exec "$CT_ID" -- bash -c 'export DEBIAN_FRONTEND=noninteractive && apt-get update -qq && apt-get -yq dist-upgrade'
              ;;
          esac
          
          echo "=== Container $CT_ID complete ==="
      loop: "{{ running_cts.stdout_lines | zip(container_os.results | default([]) | map(attribute='stdout')) | list }}"
      when: running_cts.stdout_lines | length > 0

    - name: Update running VMs (assumed Debian/Ubuntu)
      ansible.builtin.shell:
        cmd: |
          VM_ID="{{ item }}"
          echo "=== Updating VM $VM_ID ==="
          sudo /usr/sbin/qm guest exec $VM_ID -- bash -c 'export DEBIAN_FRONTEND=noninteractive && apt-get update -qq && apt-get upgrade -y -qq'
          echo "=== VM $VM_ID complete ==="
      loop: "{{ running_vms.stdout_lines }}"
      when: running_vms.stdout_lines | length > 0

    - name: Report results
      ansible.builtin.debug:
        msg: "[bwvebox] updates complete. Containers: {{ running_cts.stdout_lines | default([]) }}, VMs: {{ running_vms.stdout_lines | default([]) }}"
