#!/usr/bin/env bash

set -Eeuo pipefail
umask 077

readonly EXPECTED_HOSTNAME='sqjcmqtt02'
readonly EXPECTED_IP='10.2.203.109'
readonly ETC_DIR='/etc/emqx'
readonly CONFIG='/etc/emqx/emqx.conf'
readonly ACL='/etc/emqx/acl.conf'
readonly COOKIE='/etc/zhct/secrets/emqx.cluster-cookie'
readonly COOKIE_TRANSFER='/root/emqx.cluster-cookie.transfer'
readonly EXPECTED_COOKIE_SHA256='750bf6ce86ab809d35974f7574ea68b8410b5bdcaf01bc8e0ca70c2fe4016fad'
readonly EXPECTED_COOKIE_SIZE='65'
readonly STAGE1_LOG='/root/q142-stage1-static-preflight.log'
readonly STAGE2_SCRIPT='/root/emqx02-q142-stage2-execute-verify.sh'
readonly STAGE2_SCRIPT_SHA256='3620e06c4701fde4b9b11f573585afbd6d22f1274fd3ba00033784b5df758e47'
readonly PACKAGE_ENTRY='/root/emqx-q142-q143-sftp/emqx-q142-q143.sh'
readonly PACKAGE_ENTRY_SHA256='356f6d98d9d13baa8bea1a6e1aa0b838b1e1d5c88a0c6a228e60824d5c348aac'
readonly TARGET_PORT_RE=':(1883|8083|18083|4370|5370|8883|8084)([[:space:]]|$)'
readonly AUDIT_LOG='/root/q142-repair-etc-dir-and-retry.log'

q142_repair_mutation_started=0
q142_repair_success=0

test "${EUID}" -eq 0
test "$(hostname -s)" = "${EXPECTED_HOSTNAME}"
ip -o -4 addr show scope global | awk '{print $4}' | cut -d/ -f1 |
  grep -Fxq "${EXPECTED_IP}"

exec > >(tee "${AUDIT_LOG}") 2>&1

q142_repair_finish() {
  q142_repair_rc=$?
  trap - EXIT
  set +e
  if [[ "${q142_repair_rc}" -ne 0 &&
    "${q142_repair_mutation_started}" -eq 1 &&
    "${q142_repair_success}" -ne 1 ]]; then
    printf '%s\n' 'Q142_ETC_DIR_REPAIR_ROLLBACK_BEGIN'
    q142_repair_rollback_ok=1
    for q142_repair_unit in emqx.service mosquitto.service; do
      q142_repair_enabled=$(
        systemctl is-enabled "${q142_repair_unit}" 2>&1 || true
      )
      q142_repair_active=$(
        systemctl is-active "${q142_repair_unit}" 2>&1 || true
      )
      printf 'ROLLBACK_UNIT=%s enabled=%s active=%s\n' \
        "${q142_repair_unit}" \
        "${q142_repair_enabled}" \
        "${q142_repair_active}"
      [[ "${q142_repair_enabled}" == disabled ]] ||
        q142_repair_rollback_ok=0
      [[ "${q142_repair_active}" == inactive ]] ||
        q142_repair_rollback_ok=0
    done
    if pgrep -x beam.smp >/dev/null || pgrep -x mosquitto >/dev/null; then
      printf '%s\n' 'ROLLBACK_TARGET_PROCESSES_UNEXPECTED'
      q142_repair_rollback_ok=0
    else
      printf '%s\n' 'ROLLBACK_TARGET_PROCESSES_ZERO'
    fi
    if ss -lntupH | grep -E "${TARGET_PORT_RE}" >/dev/null; then
      printf '%s\n' 'ROLLBACK_TARGET_LISTENERS_UNEXPECTED'
      q142_repair_rollback_ok=0
    else
      printf '%s\n' 'ROLLBACK_TARGET_LISTENERS_ZERO'
    fi
    for q142_repair_runtime_dir in /var/lib/emqx /var/log/emqx; do
      if [[ ! -d "${q142_repair_runtime_dir}" ]] ||
        find "${q142_repair_runtime_dir}" -mindepth 1 -print -quit |
          grep -q .; then
        printf 'ROLLBACK_RUNTIME_DIRECTORY_NOT_EMPTY_OR_MISSING=%s\n' \
          "${q142_repair_runtime_dir}"
        q142_repair_rollback_ok=0
      else
        printf 'ROLLBACK_RUNTIME_DIRECTORY_EMPTY=%s\n' \
          "${q142_repair_runtime_dir}"
      fi
    done
    [[ -f "${CONFIG}" ]] || q142_repair_rollback_ok=0
    grep -Fq '__EMQX_CLUSTER_COOKIE__' "${CONFIG}" ||
      q142_repair_rollback_ok=0
    [[ ! -e "${COOKIE}" ]] || q142_repair_rollback_ok=0
    [[ ! -e "${ACL}" ]] || q142_repair_rollback_ok=0
    if [[ -e "${COOKIE_TRANSFER}" ]]; then
      test "$(stat -c '%U:%G:%a:%s' "${COOKIE_TRANSFER}")" = \
        "root:root:600:${EXPECTED_COOKIE_SIZE}" ||
        q142_repair_rollback_ok=0
      test "$(sha256sum "${COOKIE_TRANSFER}" | awk '{print $1}')" = \
        "${EXPECTED_COOKIE_SHA256}" ||
        q142_repair_rollback_ok=0
      printf '%s\n' 'ROLLBACK_COOKIE_TRANSFER_STATE=VALID_PRE_EXECUTE_COPY'
    else
      printf '%s\n' 'ROLLBACK_COOKIE_TRANSFER_STATE=ABSENT_AFTER_INNER_ROLLBACK'
    fi
    if [[ "${q142_repair_rollback_ok}" -eq 1 ]]; then
      chown root:root "${ETC_DIR}"
      chmod 0750 "${ETC_DIR}"
      if [[ "$(stat -c '%U:%G:%a' "${ETC_DIR}")" == root:root:750 ]]; then
        printf '%s\n' \
          'Q142_ETC_DIR_REPAIR_ROLLBACK_STATUS=PASS_ORIGINAL_DIRECTORY_STATE_RESTORED'
      else
        printf '%s\n' \
          'Q142_ETC_DIR_REPAIR_ROLLBACK_STATUS=FAIL_MANUAL_REVIEW_REQUIRED'
      fi
    else
      printf '%s\n' \
        'Q142_ETC_DIR_REPAIR_ROLLBACK_STATUS=FAIL_MANUAL_REVIEW_REQUIRED'
    fi
  fi
  printf '%s\n' 'Q142_REPAIR_ETC_DIR_AND_RETRY_END'
  printf 'Q142_REPAIR_ETC_DIR_AND_RETRY_RC=%s\n' "${q142_repair_rc}"
  exit "${q142_repair_rc}"
}
trap q142_repair_finish EXIT

printf '%s\n' 'Q142_REPAIR_ETC_DIR_AND_RETRY_BEGIN'
hostname -s
ip -br -4 addr show ens192
ip -br -4 addr show ens192 | grep -F "${EXPECTED_IP}/24"

printf '%s\n' '=== LOCKED RECEIPTS AND ASSETS ==='
test -f "${STAGE1_LOG}"
test "$(stat -c '%U:%G:%a' "${STAGE1_LOG}")" = root:root:600
grep -Fx 'Q142_STAGE1_STATIC_PREFLIGHT_PASS' "${STAGE1_LOG}"
grep -Fx 'Q142_STAGE1_STATIC_PREFLIGHT_RC=0' "${STAGE1_LOG}"
grep -Fx 'Q142_EXECUTE_NOT_RUN' "${STAGE1_LOG}"
printf '%s  %s\n' "${STAGE2_SCRIPT_SHA256}" "${STAGE2_SCRIPT}" |
  sha256sum -c -
printf '%s  %s\n' "${PACKAGE_ENTRY_SHA256}" "${PACKAGE_ENTRY}" |
  sha256sum -c -
bash "${PACKAGE_ENTRY}" --static-validate
printf '%s\n' 'LOCKED_RECEIPTS_AND_ASSETS_PASS'

printf '%s\n' '=== PRE-REPAIR SEALED STATE ==='
test "$(stat -c '%U:%G:%a' "${ETC_DIR}")" = root:root:750
test "$(id -g -n emqx)" = emqx
test -f "${CONFIG}"
grep -Fq '__EMQX_CLUSTER_COOKIE__' "${CONFIG}"
test ! -e "${COOKIE}"
test ! -e "${ACL}"
for q142_repair_unit in emqx.service mosquitto.service; do
  test "$(systemctl is-enabled "${q142_repair_unit}" 2>&1 || true)" = disabled
  test "$(systemctl is-active "${q142_repair_unit}" 2>&1 || true)" = inactive
done
test -z "$(pgrep -fa 'beam.smp|/usr/lib/emqx|mosquitto' || true)"
test -z "$(ss -lntupH | grep -E "${TARGET_PORT_RE}" || true)"
for q142_repair_runtime_dir in /var/lib/emqx /var/log/emqx; do
  test -d "${q142_repair_runtime_dir}"
  test -z "$(
    find "${q142_repair_runtime_dir}" -mindepth 1 -print -quit
  )"
done
if runuser -u emqx -- test -x "${ETC_DIR}"; then
  printf '%s\n' 'PRE_REPAIR_EMQX_USER_TRAVERSE_UNEXPECTED'
  exit 1
else
  printf '%s\n' 'PRE_REPAIR_EMQX_USER_TRAVERSE_DENIED_CONFIRMED'
fi
printf '%s\n' 'PRE_REPAIR_SEALED_STATE_PASS'

printf '%s\n' '=== COOKIE TRANSFER REUPLOAD GATE ==='
test -s "${COOKIE_TRANSFER}"
test "$(stat -c '%U:%G:%a:%s' "${COOKIE_TRANSFER}")" = \
  "root:root:600:${EXPECTED_COOKIE_SIZE}"
test "$(sha256sum "${COOKIE_TRANSFER}" | awk '{print $1}')" = \
  "${EXPECTED_COOKIE_SHA256}"
printf 'COOKIE_TRANSFER_OWNER_MODE_SIZE=root:root:600:%s\n' \
  "${EXPECTED_COOKIE_SIZE}"
printf 'COOKIE_TRANSFER_SHA256=%s\n' "${EXPECTED_COOKIE_SHA256}"
printf '%s\n' 'COOKIE_TRANSFER_VALUE_NOT_OUTPUT'

printf '%s\n' '=== MINIMAL DIRECTORY REPAIR ==='
q142_repair_mutation_started=1
chown root:emqx "${ETC_DIR}"
chmod 0750 "${ETC_DIR}"
test "$(stat -c '%U:%G:%a' "${ETC_DIR}")" = root:emqx:750
runuser -u emqx -- test -x "${ETC_DIR}"
runuser -u emqx -- test -r "${CONFIG}"
runuser -u emqx -- test -r /etc/emqx/base.hocon
printf '%s\n' 'ETC_DIR_OWNER_MODE=root:emqx:750'
printf '%s\n' 'EMQX_USER_ETC_DIR_TRAVERSE=PASS'
printf '%s\n' 'EMQX_USER_CONFIG_READ=PASS'
printf '%s\n' 'EMQX_USER_BASE_HOCON_READ=PASS'
printf '%s\n' 'DIRECTORY_REPAIR_SCOPE=NON_RECURSIVE_OWNER_GROUP_MODE_ONLY'

printf '%s\n' '=== RETRY LOCKED Q142 STAGE2 ==='
set +e
bash "${STAGE2_SCRIPT}"
q142_repair_inner_rc=$?
set -e
printf 'Q142_RETRY_INNER_STAGE2_RC=%s\n' "${q142_repair_inner_rc}"
if [[ "${q142_repair_inner_rc}" -ne 0 ]]; then
  exit "${q142_repair_inner_rc}"
fi

test "$(stat -c '%U:%G:%a' "${ETC_DIR}")" = root:emqx:750
runuser -u emqx -- test -x "${ETC_DIR}"
runuser -u emqx -- test -r "${CONFIG}"
test ! -e "${COOKIE_TRANSFER}"
printf '%s\n' 'ETC_DIR_RUNTIME_ACCESS_POSTCONDITION=PASS'
printf '%s\n' 'COOKIE_TRANSFER_CONSUMED=PASS'
printf '%s\n' 'COOKIE_VALUE_NOT_OUTPUT'
printf '%s\n' 'Q200_NETWORK_GATE=NOT_PERFORMED'
printf '%s\n' 'Q240_FORMAL_CLUSTER_ACCEPTANCE=NOT_PERFORMED'
printf '%s\n' 'KEEPALIVED_VIP=OUT_OF_SCOPE'
q142_repair_success=1
printf '%s\n' 'Q142_REPAIR_ETC_DIR_AND_RETRY_PASS'
