#!/usr/bin/env bash
set -Eeuo pipefail
umask 077
export LC_ALL=C

EXPECTED_HOSTNAME=sqjcredis01
EXPECTED_IPV4=10.2.203.112
EXPECTED_OS='openEuler release 24.03 (LTS-SP1)'
RUN_ID=${1:-}
CONFIRM=${2:-}
PACKAGE_ROOT=/opt/zhct-deploy/packages
RPM_ROOT="${PACKAGE_ROOT}/rpms"
EVIDENCE_ROOT=/var/backups/zhct-q072
EVIDENCE_DIR="${EVIDENCE_ROOT}/${RUN_ID}"
BUILD_ROOT="/var/tmp/zhct-q072-${RUN_ID}"
ARCHIVE="/root/redis01-q072-evidence-${RUN_ID}.tar.gz"
TARGET_PORT_RE=':(6379|6387|26379|26387|3000|10008|16379|16387|36379|36387)([[:space:]]|$)'

die() { printf 'ERROR: %s\n' "$*" >&2; exit 1; }
cleanup() {
  local rc=$?
  rm -rf -- "${BUILD_ROOT}"
  exit "${rc}"
}
trap cleanup EXIT

[[ "${EUID}" -eq 0 ]] || die 'must run as root'
[[ "${RUN_ID}" =~ ^q072-[0-9]{8}T[0-9]{6}[+]0800$ ]] || die 'invalid Q072 run id'
[[ "${CONFIRM}" == --execute-q072-offline-verify ]] ||
  die 'explicit Q072 flag is required'
[[ "$(hostname -s)" == "${EXPECTED_HOSTNAME}" ]] || die 'hostname mismatch'
[[ "$(tr -d '\r' </etc/openEuler-release)" == "${EXPECTED_OS}" ]] ||
  die 'OS mismatch'
[[ "$(uname -m)" == x86_64 ]] || die 'architecture mismatch'
ip -o -4 addr show scope global | awk '{print $4}' | cut -d/ -f1 |
  grep -Fxq "${EXPECTED_IPV4}" || die 'expected IPv4 is not configured'
for command_name in dnf rpm sha256sum tar make gcc unshare file ldd ss flock; do
  command -v "${command_name}" >/dev/null || die "missing command: ${command_name}"
done
[[ ! -e "${EVIDENCE_DIR}" && ! -e "${ARCHIVE}" && ! -e "${BUILD_ROOT}" ]] ||
  die 'Q072 target path already exists'
grep -Fxq 'temporary_verify=PASS' \
  /var/backups/zhct-q070/evidence/q070-20260727T132305+0800/q071-20260727T163650+0800-temporary-verify.env ||
  die 'Q071 R3 PASS receipt missing'
[[ "$(sysctl -n vm.overcommit_memory)" == 1 ]] || die 'overcommit is not 1'
grep -Fq '[never]' /sys/kernel/mm/transparent_hugepage/enabled ||
  die 'THP is not never'
for unit in orchestrator redis5 redis7 sentinel5 sentinel7; do
  ! systemctl is-active --quiet "${unit}.service" ||
    die "target unit is active: ${unit}"
done
[[ -z "$(ss -lntupH | grep -E "${TARGET_PORT_RE}" || true)" ]] ||
  die 'target listener exists'

expected_nevra=(
  'jq-0:1.8.2-1.oe2403sp1.x86_64'
  'oniguruma-0:6.9.9-1.oe2403sp1.x86_64'
  'percona-orchestrator-2:3.2.6-22.el8.x86_64'
  'percona-orchestrator-cli-2:3.2.6-22.el8.x86_64'
  'percona-orchestrator-client-2:3.2.6-22.el8.x86_64'
)
mapfile -t installed_nevra < <(
  rpm -q --qf '%{NAME}-%{EPOCHNUM}:%{VERSION}-%{RELEASE}.%{ARCH}\n' \
    jq oniguruma percona-orchestrator percona-orchestrator-cli \
    percona-orchestrator-client | sort
)
mapfile -t expected_sorted < <(printf '%s\n' "${expected_nevra[@]}" | sort)
[[ "${installed_nevra[*]}" == "${expected_sorted[*]}" ]] ||
  die 'installed NEVRA set mismatch'
(
  cd "${PACKAGE_ROOT}"
  sha256sum -c rpms.sha256
) || die 'locked RPM manifest verification failed'
mapfile -d '' rpms < <(
  find "${RPM_ROOT}" -maxdepth 1 -type f -name '*.rpm' -print0 | sort -z
)
[[ "${#rpms[@]}" -eq 5 ]] || die 'locked RPM count is not five'
printf '3ea5024766d983249e80d4aa9457c897a9f079957d0fb1f35682df233f997f32  %s\n' \
  "${PACKAGE_ROOT}/redis-5.0.14.tar.gz" | sha256sum -c -
printf '21326da3f66c0aead4c8204c0ac52ff905337a77cadd169f75ac22835ea30025  %s\n' \
  "${PACKAGE_ROOT}/redis-7.2.14.tar.gz" | sha256sum -c -

install -d -m 0700 "${EVIDENCE_DIR}" "${BUILD_ROOT}"
exec 9>/run/lock/zhct-redis01-q072.lock
flock -n 9 || die 'another Redis01 Q072 process is running'
rpm -qa | sort >"${EVIDENCE_DIR}/rpm-before.txt"
dnf history list --reverse >"${EVIDENCE_DIR}/dnf-history-before.txt"
sha256sum \
  /opt/redis/5.0.14/bin/redis-server \
  /opt/redis/5.0.14/bin/redis-sentinel \
  /opt/redis/7.2.14/bin/redis-server \
  /opt/redis/7.2.14/bin/redis-sentinel \
  /usr/bin/orchestrator >"${EVIDENCE_DIR}/runtime-before.sha256"

export Q072_RPM_LIST
printf -v Q072_RPM_LIST '%q ' "${rpms[@]}"
unshare --net bash -Eeuo pipefail -c '
  [[ -z "$(ip route show)" ]] || {
    printf "ERROR: isolated namespace has a route\n" >&2
    exit 1
  }
  printf "NETWORK_NAMESPACE_ROUTES=NONE\n"
  read -r -a local_rpms <<<"${Q072_RPM_LIST}"
  set +e
  dnf --disablerepo="*" --setopt=strict=True \
    --setopt=install_weak_deps=False --setopt=localpkg_gpgcheck=False \
    --assumeno reinstall "${local_rpms[@]}" \
    >"'"${EVIDENCE_DIR}"'/dnf-offline-reinstall-assumeno.log" 2>&1
  dnf_rc=$?
  set -e
  printf "DNF_ASSUMENO_RC=%s\n" "${dnf_rc}"
  [[ "${dnf_rc}" -eq 1 ]]
  grep -Fq "Transaction Summary" \
    "'"${EVIDENCE_DIR}"'/dnf-offline-reinstall-assumeno.log"
  grep -Eq "Reinstall[[:space:]]+5 Packages|Reinstalling:" \
    "'"${EVIDENCE_DIR}"'/dnf-offline-reinstall-assumeno.log"
  ! grep -Eiq "nothing provides|conflicting requests|transaction test error|cannot download|failed to download" \
    "'"${EVIDENCE_DIR}"'/dnf-offline-reinstall-assumeno.log"
  tar -xzf "'"${PACKAGE_ROOT}"'/redis-5.0.14.tar.gz" -C "'"${BUILD_ROOT}"'"
  tar -xzf "'"${PACKAGE_ROOT}"'/redis-7.2.14.tar.gz" -C "'"${BUILD_ROOT}"'"
  make -C "'"${BUILD_ROOT}"'/redis-5.0.14" -j"$(nproc)" CFLAGS=-fwrapv
  make -C "'"${BUILD_ROOT}"'/redis-7.2.14" -j"$(nproc)"
  "'"${BUILD_ROOT}"'/redis-5.0.14/src/redis-server" --version |
    grep -Fq "v=5.0.14"
  "'"${BUILD_ROOT}"'/redis-7.2.14/src/redis-server" --version |
    grep -Fq "v=7.2.14"
  ! ldd "'"${BUILD_ROOT}"'/redis-5.0.14/src/redis-server" | grep -Fq "not found"
  ! ldd "'"${BUILD_ROOT}"'/redis-7.2.14/src/redis-server" | grep -Fq "not found"
  printf "OFFLINE_SOURCE_REBUILD=PASS\n"
' >"${EVIDENCE_DIR}/offline-verify.stdout" \
  2>"${EVIDENCE_DIR}/offline-verify.stderr"

rpm -qa | sort >"${EVIDENCE_DIR}/rpm-after.txt"
dnf history list --reverse >"${EVIDENCE_DIR}/dnf-history-after.txt"
sha256sum \
  /opt/redis/5.0.14/bin/redis-server \
  /opt/redis/5.0.14/bin/redis-sentinel \
  /opt/redis/7.2.14/bin/redis-server \
  /opt/redis/7.2.14/bin/redis-sentinel \
  /usr/bin/orchestrator >"${EVIDENCE_DIR}/runtime-after.sha256"
cmp -s "${EVIDENCE_DIR}/rpm-before.txt" "${EVIDENCE_DIR}/rpm-after.txt" ||
  die 'RPM set changed'
cmp -s "${EVIDENCE_DIR}/dnf-history-before.txt" \
  "${EVIDENCE_DIR}/dnf-history-after.txt" || die 'DNF history changed'
cmp -s "${EVIDENCE_DIR}/runtime-before.sha256" \
  "${EVIDENCE_DIR}/runtime-after.sha256" || die 'installed runtime changed'
grep -Fxq 'NETWORK_NAMESPACE_ROUTES=NONE' \
  "${EVIDENCE_DIR}/offline-verify.stdout"
grep -Fxq 'DNF_ASSUMENO_RC=1' "${EVIDENCE_DIR}/offline-verify.stdout"
grep -Fxq 'OFFLINE_SOURCE_REBUILD=PASS' \
  "${EVIDENCE_DIR}/offline-verify.stdout"
for binary in \
  /opt/redis/5.0.14/bin/redis-server \
  /opt/redis/5.0.14/bin/redis-sentinel \
  /opt/redis/7.2.14/bin/redis-server \
  /opt/redis/7.2.14/bin/redis-sentinel \
  /usr/bin/orchestrator; do
  file "${binary}"
  ! ldd "${binary}" | grep -Fq 'not found' || die "missing library: ${binary}"
done >"${EVIDENCE_DIR}/installed-runtime-check.txt"
for unit in orchestrator redis5 redis7 sentinel5 sentinel7; do
  ! systemctl is-active --quiet "${unit}.service" ||
    die "target unit became active: ${unit}"
done
[[ -z "$(ss -lntupH | grep -E "${TARGET_PORT_RE}" || true)" ]] ||
  die 'target listener exists after Q072'

cat >"${EVIDENCE_DIR}/result.env" <<EOF
run_id=${RUN_ID}
network_namespace=NO_ROUTES
offline_rpm_reinstall_assumeno=PASS
offline_redis5_rebuild_cflags=-fwrapv
offline_redis7_rebuild_cflags=DEFAULT
installed_rpm_set_unchanged=PASS
dnf_history_unchanged=PASS
installed_runtime_sha256_unchanged=PASS
target_units=INACTIVE
target_listeners=NONE
q072=PASS
EOF
tar -czf "${ARCHIVE}" -C / "var/backups/zhct-q072/${RUN_ID}"
chmod 0600 "${ARCHIVE}"
rm -rf -- "${BUILD_ROOT}"
trap - EXIT
cat "${EVIDENCE_DIR}/offline-verify.stdout"
cat "${EVIDENCE_DIR}/result.env"
sha256sum "${ARCHIVE}"
stat -c 'archive_bytes=%s' "${ARCHIVE}"
printf 'Q072_OFFLINE_CACHE_ONLY_VERIFY=PASS\n'
