---
# Security Updates Playbook
# Automated security patches and system updates
# Usage: ansible-playbook playbooks/security_updates.yml
# Usage: ansible-playbook playbooks/security_updates.yml -e "reboot_if_required=true"
# Usage: ansible-playbook playbooks/security_updates.yml -e "security_only=true"

- name: Apply Security Updates
  hosts: "{{ host_target | default('debian_clients') }}"
  gather_facts: yes
  become: yes
  vars:
    security_only: "{{ security_only | default(true) }}"
    reboot_if_required: "{{ reboot_if_required | default(false) }}"
    backup_before_update: "{{ backup_before_update | default(true) }}"
    max_reboot_wait: "{{ max_reboot_wait | default(300) }}"
    update_docker: "{{ update_docker | default(false) }}"

  tasks:
    - name: Check if host is reachable
      ping:
      register: ping_result

    - name: Create update log directory
      file:
        path: "/var/log/ansible_updates"
        state: directory
        mode: '0755'

    - name: Get pre-update system info
      shell: |
        echo "=== PRE-UPDATE SYSTEM INFO ==="
        echo "Date: {{ ansible_date_time.iso8601 }}"
        echo "Host: {{ inventory_hostname }}"
        echo "Kernel: $(uname -r)"
        echo "Uptime: $(uptime)"
        echo ""

        echo "=== CURRENT PACKAGES ==="
        dpkg -l | grep -E "(linux-image|linux-headers)" || echo "No kernel packages found"
        echo ""

        echo "=== SECURITY UPDATES AVAILABLE ==="
        apt list --upgradable 2>/dev/null | grep -i security || echo "No security updates available"
        echo ""

        echo "=== DISK SPACE ==="
        df -h /
        echo ""

        echo "=== RUNNING SERVICES ==="
        systemctl list-units --type=service --state=running | head -10
      register: pre_update_info
      changed_when: false

    - name: Display update plan
      debug:
        msg: |
          🔒 SECURITY UPDATE PLAN
          =======================
          🖥️  Host: {{ inventory_hostname }}
          📅 Date: {{ ansible_date_time.date }}
          🔐 Security Only: {{ security_only }}
          🔄 Reboot if Required: {{ reboot_if_required }}
          💾 Backup First: {{ backup_before_update }}
          🐳 Update Docker: {{ update_docker }}

          {{ pre_update_info.stdout }}

    - name: Backup critical configs before update
      shell: |
        backup_dir="/var/backups/pre-update-{{ ansible_date_time.epoch }}"
        mkdir -p "$backup_dir"

        echo "Creating pre-update backup..."

        # Backup critical system configs
        cp -r /etc/ssh "$backup_dir/" 2>/dev/null || echo "SSH config backup failed"
        cp -r /etc/nginx "$backup_dir/" 2>/dev/null || echo "Nginx config not found"
        cp -r /etc/systemd "$backup_dir/" 2>/dev/null || echo "Systemd config backup failed"

        # Backup package list
        dpkg --get-selections > "$backup_dir/package_list.txt"

        # Backup Docker configs if they exist
        if [ -d "/opt/docker" ]; then
          tar -czf "$backup_dir/docker_configs.tar.gz" /opt/docker 2>/dev/null || echo "Docker config backup failed"
        fi

        echo "✅ Backup created at $backup_dir"
        ls -la "$backup_dir"
      register: backup_result
      when: backup_before_update | bool

    - name: Update package cache
      apt:
        update_cache: yes
        cache_valid_time: 0
      register: cache_update

    - name: Check for available security updates
      shell: |
        apt list --upgradable 2>/dev/null | grep -c security || echo "0"
      register: security_updates_count
      changed_when: false

    - name: Check for kernel updates
      shell: |
        apt list --upgradable 2>/dev/null | grep -E "(linux-image|linux-headers)" | wc -l
      register: kernel_updates_count
      changed_when: false

    - name: Apply security updates only
      apt:
        upgrade: safe
        autoremove: yes
        autoclean: yes
      register: security_update_result
      when:
        - security_only | bool
        - security_updates_count.stdout | int > 0

    - name: Apply all updates (if not security only)
      apt:
        upgrade: dist
        autoremove: yes
        autoclean: yes
      register: full_update_result
      when:
        - not security_only | bool

    - name: Update Docker (if requested)
      block:
        - name: Add Docker GPG key
          apt_key:
            url: https://download.docker.com/linux/ubuntu/gpg
            state: present

        - name: Add Docker repository
          apt_repository:
            repo: "deb [arch=amd64] https://download.docker.com/linux/ubuntu {{ ansible_distribution_release }} stable"
            state: present

        - name: Update Docker packages
          apt:
            name:
              - docker-ce
              - docker-ce-cli
              - containerd.io
            state: latest
          register: docker_update_result

        - name: Restart Docker service
          systemd:
            name: docker
            state: restarted
            enabled: yes
          when: docker_update_result.changed

      when: update_docker | bool

    - name: Check if reboot is required
      stat:
        path: /var/run/reboot-required
      register: reboot_required_file

    - name: Display reboot requirement
      debug:
        msg: |
          🔄 REBOOT STATUS
          ================
          Reboot Required: {{ reboot_required_file.stat.exists }}
          Kernel Updates: {{ kernel_updates_count.stdout }}
          Auto Reboot: {{ reboot_if_required }}

    - name: Create update report
      shell: |
        report_file="/var/log/ansible_updates/update_report_{{ ansible_date_time.epoch }}.txt"

        echo "🔒 SECURITY UPDATE REPORT - {{ inventory_hostname }}" > "$report_file"
        echo "=================================================" >> "$report_file"
        echo "Date: {{ ansible_date_time.iso8601 }}" >> "$report_file"
        echo "Host: {{ inventory_hostname }}" >> "$report_file"
        echo "Security Only: {{ security_only }}" >> "$report_file"
        echo "Reboot Required: {{ reboot_required_file.stat.exists }}" >> "$report_file"
        echo "" >> "$report_file"

        echo "=== PRE-UPDATE INFO ===" >> "$report_file"
        echo "{{ pre_update_info.stdout }}" >> "$report_file"
        echo "" >> "$report_file"

        echo "=== UPDATE RESULTS ===" >> "$report_file"
        {% if security_only %}
        {% if security_update_result is defined %}
        echo "Security updates applied: {{ security_update_result.changed }}" >> "$report_file"
        {% endif %}
        {% else %}
        {% if full_update_result is defined %}
        echo "Full system update applied: {{ full_update_result.changed }}" >> "$report_file"
        {% endif %}
        {% endif %}

        {% if update_docker and docker_update_result is defined %}
        echo "Docker updated: {{ docker_update_result.changed }}" >> "$report_file"
        {% endif %}

        echo "" >> "$report_file"
        echo "=== POST-UPDATE INFO ===" >> "$report_file"
        echo "Kernel: $(uname -r)" >> "$report_file"
        echo "Uptime: $(uptime)" >> "$report_file"
        echo "Available updates: $(apt list --upgradable 2>/dev/null | wc -l)" >> "$report_file"

        {% if backup_before_update %}
        echo "" >> "$report_file"
        echo "=== BACKUP INFO ===" >> "$report_file"
        echo "{{ backup_result.stdout }}" >> "$report_file"
        {% endif %}

        cat "$report_file"
      register: update_report

    - name: Notify about pending reboot
      debug:
        msg: |
          ⚠️  REBOOT REQUIRED
          ===================
          Host: {{ inventory_hostname }}
          Reason: System updates require reboot
          Kernel updates: {{ kernel_updates_count.stdout }}

          Manual reboot command: sudo reboot
          Or run with: -e "reboot_if_required=true"
      when:
        - reboot_required_file.stat.exists
        - not reboot_if_required | bool

    - name: Reboot system if required and authorized
      reboot:
        reboot_timeout: "{{ max_reboot_wait }}"
        msg: "Rebooting for security updates"
        pre_reboot_delay: 10
      when:
        - reboot_required_file.stat.exists
        - reboot_if_required | bool
      register: reboot_result

    - name: Wait for system to come back online
      wait_for_connection:
        timeout: "{{ max_reboot_wait }}"
        delay: 30
      when: reboot_result is defined and reboot_result.changed

    - name: Verify services after reboot
      shell: |
        echo "Verifying critical services after reboot..."
        sleep 30  # Give services time to start

        critical_services=("ssh" "docker" "tailscaled")
        failed_services=()

        for service in "${critical_services[@]}"; do
          if ! systemctl is-active --quiet "$service"; then
            failed_services+=("$service")
          fi
        done

        if [ ${#failed_services[@]} -eq 0 ]; then
          echo "✅ All critical services running after reboot"
        else
          echo "⚠️  Services needing attention: ${failed_services[*]}"
          for service in "${failed_services[@]}"; do
            echo "Attempting to start $service..."
            systemctl start "$service" || echo "Failed to start $service"
          done
        fi

        echo ""
        echo "System status:"
        echo "Uptime: $(uptime)"
        echo "Kernel: $(uname -r)"
        echo "Docker: $(docker --version 2>/dev/null || echo 'Docker not available')"
      register: post_reboot_verification
      when: reboot_result is defined and reboot_result.changed

    - name: Final security check
      shell: |
        echo "=== FINAL SECURITY STATUS ==="
        echo "Available security updates: $(apt list --upgradable 2>/dev/null | grep -c security || echo '0')"
        echo "Reboot required: $([ -f /var/run/reboot-required ] && echo 'Yes' || echo 'No')"
        echo "Last update: {{ ansible_date_time.iso8601 }}"
        echo ""

        echo "=== SYSTEM HARDENING CHECK ==="
        echo "SSH root login: $(grep PermitRootLogin /etc/ssh/sshd_config | head -1 || echo 'Not configured')"
        echo "Firewall status: $(ufw status | head -1 || echo 'UFW not available')"
        echo "Fail2ban status: $(systemctl is-active fail2ban 2>/dev/null || echo 'Not running')"
        echo "Automatic updates: $(systemctl is-enabled unattended-upgrades 2>/dev/null || echo 'Not configured')"
      register: final_security_check
      changed_when: false

    - name: Display update summary
      debug:
        msg: |

          ✅ SECURITY UPDATE COMPLETE - {{ inventory_hostname }}
          =============================================

          📅 Update Date: {{ ansible_date_time.date }}
          🔐 Security Only: {{ security_only }}
          🔄 Reboot Performed: {{ reboot_result.changed if reboot_result is defined else 'No' }}

          {{ update_report.stdout }}

          {{ final_security_check.stdout }}

          {% if post_reboot_verification is defined %}
          🔍 POST-REBOOT VERIFICATION:
          {{ post_reboot_verification.stdout }}
          {% endif %}

          📄 Full report: /var/log/ansible_updates/update_report_{{ ansible_date_time.epoch }}.txt

          🔍 Next Steps:
          - Monitor system stability
          - Check service functionality
          - Review security hardening: ansible-playbook playbooks/security_audit.yml

          =============================================

    - name: Send update notification (if configured)
      debug:
        msg: |
          📧 UPDATE NOTIFICATION
          Host: {{ inventory_hostname }}
          Status: Updates applied successfully
          Reboot: {{ 'Required' if reboot_required_file.stat.exists else 'Not required' }}
          Security updates: {{ security_updates_count.stdout }}
      when: send_notifications | default(false) | bool
