#!/usr/bin/env bash
set -euo pipefail

# CentOS 7 to CentOS Stream Migration Checklist
#
# Purpose:
#   This script helps assess readiness for a CentOS 7 -> CentOS Stream migration
#   by collecting a baseline, checking common compatibility concerns, and guiding
#   post-migration validation.
#
# Safe by design:
#   - No destructive actions
#   - No credentials or secrets
#   - No environment-specific endpoints
#   - Writes reports only when you provide an output directory
#
# Usage:
#   ./centos7-to-stream-migration-checklist.sh [options]
#
# Options:
#   -o, --output DIR   Write collected reports to DIR
#   -p, --post         Run post-migration validation checks
#   -h, --help         Show help
#
# Examples:
#   ./centos7-to-stream-migration-checklist.sh --output /root/migration-baseline
#   ./centos7-to-stream-migration-checklist.sh --post

OUTPUT_DIR=""
POST_MIGRATION=0

print_help() {
  cat <<'EOF'
CentOS 7 to CentOS Stream Migration Checklist

Usage:
  centos7-to-stream-migration-checklist.sh [options]

Options:
  -o, --output DIR   Write collected reports to DIR
  -p, --post         Run post-migration validation checks
  -h, --help         Show this help message
EOF
}

log() {
  printf '%s\n' "$*"
}

warn() {
  printf 'WARN: %s\n' "$*" >&2
}

require_root_or_warn() {
  if [[ ${EUID:-$(id -u)} -ne 0 ]]; then
    warn "Not running as root. Some checks may be limited."
  fi
}

safe_run() {
  local label="$1"
  shift
  log "\n==> ${label}"
  if "$@"; then
    log "OK: ${label}"
  else
    warn "Check failed or unavailable: ${label}"
  fi
}

collect_to_file() {
  local file="$1"
  shift
  local cmd=("$@")
  if command -v "${cmd[0]}" >/dev/null 2>&1; then
    "${cmd[@]}" > "$file" 2>&1 || true
  else
    printf 'Command not available: %s\n' "${cmd[0]}" > "$file"
  fi
}

preflight_checks() {
  log "CentOS 7 to CentOS Stream migration readiness checks"

  safe_run "Operating system release info" bash -lc 'cat /etc/centos-release 2>/dev/null || cat /etc/redhat-release 2>/dev/null || uname -a'
  safe_run "Kernel version" uname -r
  safe_run "Uptime" uptime
  safe_run "Current SELinux mode" bash -lc 'getenforce 2>/dev/null || echo "getenforce not available"'
  safe_run "Enabled services" bash -lc 'systemctl list-unit-files --state=enabled 2>/dev/null | sed -n "1,40p" || echo "systemctl not available"'
  safe_run "Listening ports" bash -lc 'ss -tulpn 2>/dev/null | sed -n "1,80p" || echo "ss not available"'
  safe_run "Firewall state" bash -lc 'firewall-cmd --state 2>/dev/null || echo "firewalld or firewall-cmd not available"'
  safe_run "Firewall rules" bash -lc 'firewall-cmd --list-all 2>/dev/null || echo "Unable to read firewalld settings"'
  safe_run "Mounted filesystems" bash -lc 'findmnt 2>/dev/null || mount'
  safe_run "Repository list" bash -lc 'yum repolist all 2>/dev/null || dnf repolist all 2>/dev/null || echo "yum/dnf repolist unavailable"'
  safe_run "Installed packages sample" bash -lc 'rpm -qa 2>/dev/null | sort | sed -n "1,80p" || echo "rpm not available"'
  safe_run "Network addresses" ip addr show
  safe_run "Default routes" ip route show

  log "\nChecklist prompts:"
  log "- Confirm application/vendor support for CentOS Stream target versions."
  log "- Verify internal mirrors/proxies and repository availability."
  log "- Identify custom packages, third-party agents, kernel modules, and local scripts."
  log "- Validate SELinux, firewall, SSH policy, and privileged access model."
  log "- Confirm backup and rollback readiness with a tested restore path."
  log "- Capture any service-specific health checks before migration."
}

write_baseline_reports() {
  local dir="$1"
  mkdir -p "$dir"

  log "Writing baseline reports to: $dir"
  collect_to_file "$dir/os-release.txt" bash -lc 'cat /etc/centos-release 2>/dev/null || cat /etc/redhat-release 2>/dev/null || uname -a'
  collect_to_file "$dir/kernel.txt" uname -r
  collect_to_file "$dir/uptime.txt" uptime
  collect_to_file "$dir/selinux-mode.txt" bash -lc 'getenforce 2>/dev/null || echo "getenforce not available"'
  collect_to_file "$dir/enabled-services.txt" bash -lc 'systemctl list-unit-files --state=enabled 2>/dev/null || echo "systemctl not available"'
  collect_to_file "$dir/listening-ports.txt" bash -lc 'ss -tulpn 2>/dev/null || echo "ss not available"'
  collect_to_file "$dir/firewalld.txt" bash -lc 'firewall-cmd --list-all 2>/dev/null || echo "firewalld not available or inaccessible"'
  collect_to_file "$dir/mounts.txt" bash -lc 'findmnt 2>/dev/null || mount'
  collect_to_file "$dir/repos.txt" bash -lc 'yum repolist all 2>/dev/null || dnf repolist all 2>/dev/null || echo "yum/dnf repolist unavailable"'
  collect_to_file "$dir/packages.txt" bash -lc 'rpm -qa 2>/dev/null | sort || echo "rpm not available"'
  collect_to_file "$dir/network.txt" ip addr show
  collect_to_file "$dir/routes.txt" ip route show

  cat > "$dir/README.txt" <<'EOF'
Baseline report bundle for CentOS 7 to CentOS Stream migration.

Use these files to compare pre- and post-migration state:
- os-release.txt
- kernel.txt
- uptime.txt
- selinux-mode.txt
- enabled-services.txt
- listening-ports.txt
- firewalld.txt
- mounts.txt
- repos.txt
- packages.txt
- network.txt
- routes.txt

Remember:
- This is documentation, not a rollback mechanism.
- Pair these reports with a tested backup or snapshot.
EOF
}

post_migration_checks() {
  log "Post-migration validation checks"

  safe_run "Operating system release info" bash -lc 'cat /etc/centos-release 2>/dev/null || cat /etc/redhat-release 2>/dev/null || uname -a'
  safe_run "Kernel version" uname -r
  safe_run "SELinux mode" bash -lc 'getenforce 2>/dev/null || echo "getenforce not available"'
  safe_run "Critical filesystems mounted" bash -lc 'findmnt -rn 2>/dev/null | sed -n "1,40p" || mount'
  safe_run "SSH service status" bash -lc 'systemctl is-active sshd 2>/dev/null || systemctl is-active ssh 2>/dev/null || echo "sshd/ssh status unavailable"'
  safe_run "Network listeners" bash -lc 'ss -tulpn 2>/dev/null | sed -n "1,80p" || echo "ss not available"'
  safe_run "Firewall runtime state" bash -lc 'firewall-cmd --state 2>/dev/null || echo "firewalld not available"'
  safe_run "Recent journal errors" bash -lc 'journalctl -p err -b --no-pager 2>/dev/null | sed -n "1,40p" || echo "journalctl not available"'
  safe_run "Scheduled jobs" bash -lc 'systemctl list-timers --all 2>/dev/null | sed -n "1,40p" || echo "timers not available"'

  log "\nValidation prompts:"
  log "- Confirm the application health check returns expected output."
  log "- Verify log files do not show repeated SELinux denials or dependency failures."
  log "- Check that scheduled jobs and timers fire at the expected times."
  log "- Confirm outbound connectivity to approved package/update endpoints if applicable."
  log "- Compare listening ports against the pre-migration baseline."
  log "- Validate administrative SSH access and account restrictions."
}

main() {
  require_root_or_warn

  while [[ $# -gt 0 ]]; do
    case "$1" in
      -o|--output)
        if [[ $# -lt 2 ]]; then
          echo "Error: --output requires a directory path" >&2
          exit 1
        fi
        OUTPUT_DIR="$2"
        shift 2
        ;;
      -p|--post)
        POST_MIGRATION=1
        shift
        ;;
      -h|--help)
        print_help
        exit 0
        ;;
      *)
        echo "Unknown argument: $1" >&2
        print_help >&2
        exit 1
        ;;
    esac
  done

  if [[ $POST_MIGRATION -eq 1 ]]; then
    post_migration_checks
  else
    preflight_checks
  fi

  if [[ -n "$OUTPUT_DIR" ]]; then
    write_baseline_reports "$OUTPUT_DIR"
  fi

  log "\nDone."
}

main "$@"