diff --git a/install.sh b/install.sh index ef1d27f..45ea1f5 100644 --- a/install.sh +++ b/install.sh @@ -1,6 +1,6 @@ #!/bin/bash -### version: 1.9.0 +### version: 1.9.1 # ~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.# # Nightscout Mikr.us setup script # @@ -22,6 +22,7 @@ #======================================= REQUIRED_NODE_VERSION=18.0.0 +REQUIRED_DOTENV_VERSION=1.3.0 LOGTO=/dev/null NIGHTSCOUT_ROOT_DIR=/srv/nightscout CONFIG_ROOT_DIR=/srv/nightscout/config @@ -39,18 +40,20 @@ WATCHDOG_LOG_FILE=/srv/nightscout/data/watchdog.log WATCHDOG_FAILURES_FILE=/srv/nightscout/data/watchdog-failures.log WATCHDOG_CRON_LOG=/srv/nightscout/data/watchdog-cron.log SUPPORT_LOG=/srv/nightscout/data/support.log +EVENTS_DB=/srv/nightscout/data/events.env UPDATE_CHANNEL_FILE=/srv/nightscout/data/update_channel MONGO_DB_DIR=/srv/nightscout/data/mongodb TOOL_FILE=/srv/nightscout/tools/nightscout-tool TOOL_LINK=/usr/bin/nightscout-tool UPDATES_DIR=/srv/nightscout/updates UPDATE_CHANNEL=master -DISK_LOW_WARNING=838860800 # == 800 MiB -DISK_LOW_MAIL=5184000 # == 60 days in seconds +DISK_LOW_WARNING=838860800 # == 800 MiB +DISK_LOW_MAIL=5184000 # == 60 days in seconds DISK_CRITICAL_WARNING=104857600 # == 100 MiB -DISK_CRITICAL_MAIL=604800 # == 7 days in seconds -SCRIPT_VERSION="1.9.0" #auto-update -SCRIPT_BUILD_TIME="2024.10.12" #auto-update +DISK_CRITICAL_MAIL=604800 # == 7 days in seconds +DOCKER_DOWN_MAIL=604800 # == 7 days in seconds +SCRIPT_VERSION="1.9.1" #auto-update +SCRIPT_BUILD_TIME="2024.10.18" #auto-update #======================================= # SETUP @@ -165,6 +168,8 @@ uni_confirm_ed=" $(printf '\U1F4DD') Edytuj " uni_install=" $(printf '\U1F680') Instaluj " uni_resign=" $(printf '\U1F6AB') Rezygnuję " uni_send=" $(printf '\U1F4E7') Wyślij " +uni_delete=" $(printf '\U1F5D1') Usuń " +uni_leave_logs=" $(printf '\U1F4DC') Zostaw " uni_ns_ok="$(printf '\U1F7E2') działa" uni_watchdog_ok="$(printf '\U1F415') Nightscout działa" @@ -248,6 +253,174 @@ exit_on_no_cancel() { fi } +event_mark() { + local eventName=$1 + local eventTime=$(date -u +"%Y-%m-%dT%H:%M:%SZ") + mkdir -p "/srv/nightscout/data" >>"$LOGTO" 2>&1 + dotenv-tool -r -i "${EVENTS_DB}" -m "${eventName}=${eventTime}" +} + +join_by() { + local d=${1-} f=${2-} + if shift 2; then + printf %s "$f" "${@/#/$d}" + fi +} + +event_label() { + case $1 in + cleanup) + echo "Czyszczenie" + ;; + install) + echo "Instalacja" + ;; + update_system) + echo "Aktualizacja systemu" + ;; + update_tools) + echo "Aktualizacja narzędzia" + ;; + update_containers) + echo "Aktualizacja kontenerów" + ;; + uninstall) + echo "Odinstalowanie" + ;; + remove_containers) + echo "Usunięcie kontenerów" + ;; + remove_db_data) + echo "Usunięcie danych bazy" + ;; + remove_all_data) + echo "Usunięcie danych" + ;; + change_ns_version) + echo "Zmiana wersji Nightscout" + ;; + edit_env_manual) + echo "Edycja konfiguracji" + ;; + restart_both) + echo "Wymuszony restart NS+DB" + ;; + restart_ns) + echo "Wymuszony restart NS" + ;; + last_disk_warning) + echo "Brak miejsca" + ;; + last_disk_critical) + echo "Krytyczny brak miejsca" + ;; + last_docker_down) + echo "Awaria Dockera" + ;; + last_server_restart_needed) + echo "Potrzebny restart serwera" + ;; + *) + echo "$1" + ;; + esac +} + +lpad_text() { + local inText="$1" + local len=${#inText} + local spaces=" " + echo "${spaces:0:$(($2 - len))}$1" +} + +event_count() { + if [ ! -f ${EVENTS_DB} ]; then + echo "0" + else + local eventsJSON=$(dotenv-tool parse -r -f "${EVENTS_DB}") + local eventsKeysStr=$(echo "${eventsJSON}" | jq -r ".values | keys[]") + local eventsCount=${#eventsKeysStr} + if ((eventsCount > 0)); then + mapfile -t eventList < <(echo "${eventsKeysStr}") + echo "${#eventList}" + else + echo "0" + fi + fi +} + +event_list() { + if [ ! -f ${EVENTS_DB} ]; then + echo "Nie odnotowano zdarzeń" + else + local eventsJSON=$(dotenv-tool parse -r -f "${EVENTS_DB}") + local eventsKeysStr=$(echo "${eventsJSON}" | jq -r ".values | keys[]") + local eventsCount=${#eventsKeysStr} + + if ((eventsCount > 0)); then + mapfile -t eventList < <(echo "${eventsKeysStr}") + + local namesTab=() + local labelsTab=() + local valuesTab=() + for eventId in "${eventList[@]}"; do + mapfile -t -d '_' eventIdSplit <<<"${eventId}" + local eventTail=$(echo "${eventIdSplit[-1]}" | tr -d '\n') + unset "eventIdSplit[-1]" + printf -v eventBase '%s_' "${eventIdSplit[@]}" + local eventName="${eventBase%_}" + if [ ${#eventIdSplit[@]} -eq 0 ]; then + eventName="$eventTail" + eventTail="" + fi + + if [[ "$eventTail" == "start" ]] || [[ "$eventTail" == "end" ]]; then + if [[ ! " ${namesTab[*]} " =~ [[:space:]]${eventName}[[:space:]] ]]; then + namesTab+=("${eventName}") + local startVar=$(echo "$eventsJSON" | jq -r ".values.${eventName}_start") + local endVar=$(echo "$eventsJSON" | jq -r ".values.${eventName}_end") + local joinedVar="od: $startVar do: $endVar" + local fixedVar=$(echo "$joinedVar" | sed -E -e "s/ ?(od|do): null ?//g") + valuesTab+=("$fixedVar") + fi + else + if [[ "$eventTail" == "set" ]] || [[ "$eventTail" == "clear" ]]; then + if [[ ! " ${namesTab[*]} " =~ [[:space:]]${eventName}[[:space:]] ]]; then + namesTab+=("${eventName}") + local startVar=$(echo "$eventsJSON" | jq -r ".values.${eventName}_set") + local endVar=$(echo "$eventsJSON" | jq -r ".values.${eventName}_clear") + local joinedVar="od: $startVar zdjęto: $endVar" + local fixedVar=$(echo "$joinedVar" | sed -E -e "s/ ?(od|zdjęto): null ?//g") + valuesTab+=("$fixedVar") + fi + else + namesTab+=("${eventId}") + local exactVar=$(echo "$eventsJSON" | jq -r ".values.${eventId}") + valuesTab+=("$exactVar") + fi + fi + done + + local maxLen=0 + + for ((i = 0; i < ${#namesTab[@]}; i++)); do + local eventLab="$(event_label "${namesTab[$i]}")" + local labelLen=${#eventLab} + maxLen=$((labelLen > maxLen ? labelLen : maxLen)) + labelsTab+=("$eventLab") + done + + maxLen=$((maxLen + 1)) + + for ((i = 0; i < ${#namesTab[@]}; i++)); do + echo "$(lpad_text "${labelsTab[$i]}" "$maxLen") = ${valuesTab[$i]}" + done + else + echo "Nie odnotowano zdarzeń" + fi + fi +} + get_since_last_time() { local actionName=$1 local actionFile="${DATA_ROOT_DIR}/last_${actionName}" @@ -264,13 +437,15 @@ set_last_time() { local actionName=$1 local actionFile="${DATA_ROOT_DIR}/last_${actionName}" local nowDate="$(date +'%s')" - echo "$nowDate" > "$actionFile" + echo "$nowDate" >"$actionFile" + event_mark "last_${actionName}_set" } clear_last_time() { local actionName=$1 local actionFile="${DATA_ROOT_DIR}/last_${actionName}" - rm -f "$actionFile" + rm -f "$actionFile" + event_mark "last_${actionName}_clear" } #======================================= @@ -286,8 +461,8 @@ echo_progress() { if [ "$realProg" -eq "0" ]; then local progrsec=$(((countr * realStart) / (3 * firstPhaseSecs))) - if [ $progrsec -lt "$realStart" ]; then - echo $progrsec + if [ "$progrsec" -lt "$realStart" ]; then + echo "$progrsec" else echo "$realStart" fi @@ -306,7 +481,7 @@ process_gauge() { while true; do echo 0 while kill -0 "$thepid" >/dev/null 2>&1; do - eval "$2" $num + eval "$2" "$num" num=$((num + 1)) sleep 0.3 done @@ -439,11 +614,11 @@ yesnodlg_base() { local padw=$((mwidth + rpad)) if [[ "$defaultbtn" == "y" ]]; then - whiptail --title "$title" --yesno "$(center_multiline $padw "$msg")" \ + whiptail --title "$title" --yesno "$(center_multiline "$padw" "$msg")" \ --yes-button "$ybtn" --no-button "$nbtn" \ $((linec + 7)) $((padw + 4)) else - whiptail --title "$title" --yesno --defaultno "$(center_multiline $padw "$msg")" \ + whiptail --title "$title" --yesno --defaultno "$(center_multiline "$padw" "$msg")" \ --yes-button "$ybtn" --no-button "$nbtn" \ $((linec + 7)) $((padw + 4)) fi @@ -482,7 +657,7 @@ setup_update_repo() { if [ "$aptGetWasUpdated" -eq "0" ]; then aptGetWasUpdated=1 ohai "Updating package repository" - apt-get -yq update >>$LOGTO 2>&1 + apt-get -yq update >>"$LOGTO" 2>&1 fi } @@ -496,7 +671,7 @@ test_node() { # $2 package name add_if_not_ok() { local RESULT=$? - if [ $RESULT -eq 0 ]; then + if [ "$RESULT" -eq 0 ]; then msgcheck "$1 installed" else packages+=("$2") @@ -505,11 +680,11 @@ add_if_not_ok() { add_if_not_ok_cmd() { local RESULT=$? - if [ $RESULT -eq 0 ]; then + if [ "$RESULT" -eq 0 ]; then msgcheck "$1 installed" else ohai "Installing $1..." - eval "$2" >>$LOGTO 2>&1 && msgcheck "Installing $1 successfull" + eval "$2" >>"$LOGTO" 2>&1 && msgcheck "Installing $1 successfull" fi } @@ -534,8 +709,19 @@ check_jq() { } check_dotenv() { - dotenv-tool -v >/dev/null 2>&1 - add_if_not_ok_cmd "dotenv-tool" "npm install -g dotenv-tool --registry https://npm.dzienia.pl" + if dotenv-tool -v >/dev/null 2>&1; then + local dotEnvVersion="$(dotenv-tool -v 2>/dev/null)" + if version_ge "$(major_minor "${dotEnvVersion}")" \ + "$(major_minor "${REQUIRED_DOTENV_VERSION}")"; then + msgcheck "dotenv-tool installed (${dotEnvVersion})" + else + ohai "Updating dotenv-tool (from: ${dotEnvVersion})" + eval "npm install -g dotenv-tool --registry https://npm.dzienia.pl" >>"$LOGTO" 2>&1 && msgcheck "Updating dotenv-tool successfull" + fi + else + ohai "Installing dotenv-tool..." + eval "npm install -g dotenv-tool --registry https://npm.dzienia.pl" >>"$LOGTO" 2>&1 && msgcheck "Installing dotenv-tool successfull" + fi } check_ufw() { @@ -566,7 +752,7 @@ setup_provisional_key() { ohai "Generating provisional log encryption key" local randPass=$(openssl rand -base64 30) local fixedPass=$(echo "$randPass" | sed -e 's/[+\/]/-/g') - echo "tymczasowe-${fixedPass}" >$LOG_ENCRYPTION_KEY_FILE + echo "tymczasowe-${fixedPass}" >"$LOG_ENCRYPTION_KEY_FILE" msgcheck "Provisional key generated" } @@ -575,7 +761,7 @@ setup_security() { # -------------------- # JAKIŚ klucz istnieje # -------------------- - local logKey=$(<$LOG_ENCRYPTION_KEY_FILE) + local logKey=$(<"$LOG_ENCRYPTION_KEY_FILE") local regexTemp='tymczasowe-' # ----------------------- @@ -585,9 +771,9 @@ setup_security() { msgerr "Using provisional key" test_diceware local RESULT=$? - if [ $RESULT -eq 0 ]; then + if [ "$RESULT" -eq 0 ]; then ohai "Generating proper log encryption file..." - diceware -n 5 -d - >$LOG_ENCRYPTION_KEY_FILE + diceware -n 5 -d - >"$LOG_ENCRYPTION_KEY_FILE" msgcheck "Key generated" else msgerr "Required tool (diceware) still cannot be installed - apt is locked!" @@ -603,9 +789,9 @@ setup_security() { msgerr "Encryption key empty or too short, generating better one" test_diceware local RESULT=$? - if [ $RESULT -eq 0 ]; then + if [ "$RESULT" -eq 0 ]; then ohai "Generating proper log encryption file..." - diceware -n 5 -d - >$LOG_ENCRYPTION_KEY_FILE + diceware -n 5 -d - >"$LOG_ENCRYPTION_KEY_FILE" msgcheck "Key generated" else msgerr "Generating provisional key while diceware tool is not installed" @@ -623,9 +809,9 @@ setup_security() { test_diceware local RESULT=$? - if [ $RESULT -eq 0 ]; then + if [ "$RESULT" -eq 0 ]; then ohai "Generating log encryption key..." - diceware -n 5 -d - >$LOG_ENCRYPTION_KEY_FILE + diceware -n 5 -d - >"$LOG_ENCRYPTION_KEY_FILE" msgcheck "Key generated" else msgerr "Generating provisional key while diceware tool is not installed" @@ -640,14 +826,14 @@ setup_packages() { # shellcheck disable=SC2068 (ifIsSet packages && setup_update_repo && ohai "Installing packages: ${packages[@]}" && - apt-get -yq install ${packages[@]} >>$LOGTO 2>&1 && + apt-get -yq install ${packages[@]} >>"$LOGTO" 2>&1 && msgcheck "Install successfull") || msgok "All required packages already installed" } setup_node() { test_node local RESULT=$? - if [ $RESULT -eq 0 ]; then + if [ "$RESULT" -eq 0 ]; then msgcheck "Node installed in correct version" else ohai "Cleaning old Node.js" @@ -656,17 +842,17 @@ setup_node() { apt-get -yq --fix-broken install apt-get -yq update apt-get -yq remove nodejs nodejs-doc libnode* - } >>$LOGTO 2>&1 + } >>"$LOGTO" 2>&1 ohai "Preparing Node.js setup" curl -fsSL https://deb.nodesource.com/setup_lts.x | sudo -E bash - >/dev/null 2>&1 ohai "Installing Node.js" - apt-get install -y nodejs >>$LOGTO 2>&1 + apt-get install -y nodejs >>"$LOGTO" 2>&1 test_node local RECHECK=$? - if [ $RECHECK -ne 0 ]; then + if [ "$RECHECK" -ne 0 ]; then msgerr "Nie udało się zainstalować Node.js" @@ -683,7 +869,7 @@ setup_node() { setup_users() { id -u mongodb &>/dev/null local RESULT=$? - if [ $RESULT -eq 0 ]; then + if [ "$RESULT" -eq 0 ]; then msgcheck "Mongo DB user detected" else ohai "Configuring Mongo DB user" @@ -693,11 +879,12 @@ setup_users() { setup_dir_structure() { ohai "Configuring folder structure" - mkdir -p $MONGO_DB_DIR + mkdir -p "$MONGO_DB_DIR" mkdir -p /srv/nightscout/config mkdir -p /srv/nightscout/tools - mkdir -p $UPDATES_DIR - chown -R mongodb:root $MONGO_DB_DIR + mkdir -p /srv/nightscout/data + mkdir -p "$UPDATES_DIR" + chown -R mongodb:root "$MONGO_DB_DIR" } setup_firewall() { @@ -709,7 +896,7 @@ setup_firewall() { ufw allow OpenSSH ufw allow ssh - } >>$LOGTO 2>&1 + } >>"$LOGTO" 2>&1 host=$(hostname) host=${host:1} @@ -718,30 +905,30 @@ setup_firewall() { port2=$((20000 + host)) port3=$((30000 + host)) - if ufw allow $port1 >>$LOGTO 2>&1; then + if ufw allow "$port1" >>"$LOGTO" 2>&1; then msgcheck "Do regul firewalla poprawnie dodano port $port1" else msgerr "Blad dodawania $port1 do regul firewalla" fi - if ufw allow $port2 >>$LOGTO 2>&1; then + if ufw allow "$port2" >>"$LOGTO" 2>&1; then msgcheck "Do regul firewalla poprawnie dodano port $port2" else msgerr "Blad dodawania $port2 do regul firewalla" fi - if ufw allow $port3 >>$LOGTO 2>&1; then + if ufw allow "$port3" >>"$LOGTO" 2>&1; then msgcheck "Do regul firewalla poprawnie dodano port $port3" else msgerr "Blad dodawania $port3 do regul firewalla" fi - ufw --force enable >>$LOGTO 2>&1 + ufw --force enable >>"$LOGTO" 2>&1 } setup_firewall_for_ns() { - ns_external_port=$(dotenv-tool -r get -f $ENV_FILE_DEP "NS_PORT") - if ufw allow "$ns_external_port" >>$LOGTO 2>&1; then + ns_external_port=$(dotenv-tool -r get -f "$ENV_FILE_DEP" "NS_PORT") + if ufw allow "$ns_external_port" >>"$LOGTO" 2>&1; then msgcheck "Do regul firewalla poprawnie dodano port Nightscout: $ns_external_port" else msgerr "Blad dodawania portu Nightscout: $ns_external_port do reguł firewalla" @@ -777,23 +964,23 @@ get_space_info() { } install_containers() { - docker-compose --env-file /srv/nightscout/config/deployment.env -f /srv/nightscout/config/docker-compose.yml up --no-recreate -d >>$LOGTO 2>&1 + docker-compose --env-file /srv/nightscout/config/deployment.env -f /srv/nightscout/config/docker-compose.yml up --no-recreate -d >>"$LOGTO" 2>&1 } update_containers() { - docker-compose --env-file /srv/nightscout/config/deployment.env -f /srv/nightscout/config/docker-compose.yml pull >>$LOGTO 2>&1 - docker-compose --env-file /srv/nightscout/config/deployment.env -f /srv/nightscout/config/docker-compose.yml up -d >>$LOGTO 2>&1 + docker-compose --env-file /srv/nightscout/config/deployment.env -f /srv/nightscout/config/docker-compose.yml pull >>"$LOGTO" 2>&1 + docker-compose --env-file /srv/nightscout/config/deployment.env -f /srv/nightscout/config/docker-compose.yml up -d >>"$LOGTO" 2>&1 } install_containers_progress() { local created=$(docker container ls -f 'status=created' -f name=ns-server -f name=ns-database | wc -l) local current=$(docker container ls -f 'status=running' -f name=ns-server -f name=ns-database | wc -l) local progr=$(((current - 1) * 2 + (created - 1))) - echo_progress $progr 6 50 "$1" 60 + echo_progress "$progr" 6 50 "$1" 60 } uninstall_containers() { - docker-compose --env-file /srv/nightscout/config/deployment.env -f /srv/nightscout/config/docker-compose.yml down >>$LOGTO 2>&1 + docker-compose --env-file /srv/nightscout/config/deployment.env -f /srv/nightscout/config/docker-compose.yml down >>"$LOGTO" 2>&1 } uninstall_containers_progress() { @@ -803,31 +990,31 @@ uninstall_containers_progress() { if [ "$(((running - 1) + (current - 1)))" -eq "0" ]; then echo_progress 3 3 50 "$1" 15 else - echo_progress $progr 3 50 "$1" 15 + echo_progress "$progr" 3 50 "$1" 15 fi } source_admin() { if [[ -f $ENV_FILE_ADMIN ]]; then # shellcheck disable=SC1090 - source $ENV_FILE_ADMIN + source "$ENV_FILE_ADMIN" msgok "Imported admin config" fi } download_conf() { - download_if_not_exists "deployment config" $ENV_FILE_DEP "https://gitea.dzienia.pl/shared/mikrus-installer/raw/branch/$UPDATE_CHANNEL/templates/deployment.env" - download_if_not_exists "nightscout config" $ENV_FILE_NS "https://gitea.dzienia.pl/shared/mikrus-installer/raw/branch/$UPDATE_CHANNEL/templates/nightscout.env" - download_if_not_exists "docker compose file" $DOCKER_COMPOSE_FILE "https://gitea.dzienia.pl/shared/mikrus-installer/raw/branch/$UPDATE_CHANNEL/templates/docker-compose.yml" - download_if_not_exists "profanity database" $PROFANITY_DB_FILE "https://gitea.dzienia.pl/shared/mikrus-installer/raw/branch/profanity/templates/profanity.db" - download_if_not_exists "reservation database" $RESERVED_DB_FILE "https://gitea.dzienia.pl/shared/mikrus-installer/raw/branch/profanity/templates/reserved.db" + download_if_not_exists "deployment config" "$ENV_FILE_DEP" "https://gitea.dzienia.pl/shared/mikrus-installer/raw/branch/$UPDATE_CHANNEL/templates/deployment.env" + download_if_not_exists "nightscout config" "$ENV_FILE_NS" "https://gitea.dzienia.pl/shared/mikrus-installer/raw/branch/$UPDATE_CHANNEL/templates/nightscout.env" + download_if_not_exists "docker compose file" "$DOCKER_COMPOSE_FILE" "https://gitea.dzienia.pl/shared/mikrus-installer/raw/branch/$UPDATE_CHANNEL/templates/docker-compose.yml" + download_if_not_exists "profanity database" "$PROFANITY_DB_FILE" "https://gitea.dzienia.pl/shared/mikrus-installer/raw/branch/profanity/templates/profanity.db" + download_if_not_exists "reservation database" "$RESERVED_DB_FILE" "https://gitea.dzienia.pl/shared/mikrus-installer/raw/branch/profanity/templates/reserved.db" } download_tools() { download_if_not_exists "update stamp" "$UPDATES_DIR/updated" "https://gitea.dzienia.pl/shared/mikrus-installer/raw/branch/$UPDATE_CHANNEL/updated" if ! [[ -f $TOOL_FILE ]]; then - download_if_not_exists "nightscout-tool file" $TOOL_FILE "https://gitea.dzienia.pl/shared/mikrus-installer/raw/branch/$UPDATE_CHANNEL/install.sh" + download_if_not_exists "nightscout-tool file" "$TOOL_FILE" "https://gitea.dzienia.pl/shared/mikrus-installer/raw/branch/$UPDATE_CHANNEL/install.sh" local timestamp=$(date +%s) echo "$timestamp" >"$UPDATES_DIR/timestamp" else @@ -839,8 +1026,8 @@ download_tools() { ln -s "$TOOL_FILE" "$TOOL_LINK" fi - chmod +x $TOOL_FILE - chmod +x $TOOL_LINK + chmod +x "$TOOL_FILE" + chmod +x "$TOOL_LINK" } extract_version() { @@ -915,20 +1102,20 @@ update_if_needed() { msgComp="$(printf "\U1F534") $compLocalVer $(printf "\U27A1") $compOnlineVer" fi - if [ $changed -eq 0 ]; then + if [ "$changed" -eq 0 ]; then if [ $# -eq 1 ]; then whiptail --title "Aktualizacja skryptów" --msgbox "$1" 7 50 fi else local okTxt="" - if [ $redeploy -gt 0 ]; then + if [ "$redeploy" -gt 0 ]; then okTxt="\n\n $(printf "\U26A0") Aktualizacja spowoduje też restart i aktualizację kontenerów $(printf "\U26A0")" fi whiptail --title "Aktualizacja skryptów" --yesno "Zalecana jest aktualizacja plików:\n\n${uni_bullet}Skrypt instalacyjny: $msgInst \n${uni_bullet}Konfiguracja deploymentu: $msgDep\n${uni_bullet}Konfiguracja Nightscout: $msgNs \n${uni_bullet}Kompozycja usług: $msgComp $okTxt" \ --yes-button "$uni_confirm_upd" --no-button "$uni_resign" 15 70 if ! [ $? -eq 1 ]; then - if [ $redeploy -gt 0 ]; then + if [ "$redeploy" -gt 0 ]; then docker_compose_down fi @@ -968,7 +1155,7 @@ update_if_needed() { } about_dialog() { - LOG_KEY=$(<$LOG_ENCRYPTION_KEY_FILE) + LOG_KEY=$(<"$LOG_ENCRYPTION_KEY_FILE") okdlg "O tym narzędziu..." \ "$(printf '\U1F9D1') (c) 2023 Dominik Dzienia" \ "${NL}$(printf '\U1F4E7') dominik.dzienia@gmail.com" \ @@ -1026,7 +1213,7 @@ prompt_mikrus_host() { done ohai "Updating admin config (host)" - dotenv-tool -pmr -i $ENV_FILE_ADMIN -- "MIKRUS_HOST=$MIKRUS_HOST" + dotenv-tool -pmr -i "$ENV_FILE_ADMIN" -- "MIKRUS_HOST=$MIKRUS_HOST" fi } @@ -1072,12 +1259,12 @@ prompt_mikrus_apikey() { fi ohai "Updating admin config (api key)" - dotenv-tool -pmr -i $ENV_FILE_ADMIN -- "MIKRUS_APIKEY=$MIKRUS_APIKEY" + dotenv-tool -pmr -i "$ENV_FILE_ADMIN" -- "MIKRUS_APIKEY=$MIKRUS_APIKEY" fi } prompt_api_secret() { - API_SECRET=$(dotenv-tool -r get -f $ENV_FILE_NS "API_SECRET") + API_SECRET=$(dotenv-tool -r get -f "$ENV_FILE_NS" "API_SECRET") if ! [[ "$API_SECRET" =~ [a-zA-Z0-9%+=./:=@_]{12,} ]]; then freshInstall=$((freshInstall + 1)) @@ -1124,7 +1311,7 @@ prompt_api_secret() { fi if [[ "$API_SECRET" == "$API_SECRET_CHECK" ]]; then ohai "Updating nightscout config (api secret)" - dotenv-tool -pmr -i $ENV_FILE_NS -- "API_SECRET=$API_SECRET" + dotenv-tool -pmr -i "$ENV_FILE_NS" -- "API_SECRET=$API_SECRET" break 2 else whiptail --title "$uni_excl Nieprawidłowe API SECRET $uni_excl" --yesno "Podana wartości API SECRET różni się od poprzedniej!\nChcesz podać ponownie?\n" --yes-button "$uni_reenter" --no-button "$uni_noenter" 9 60 @@ -1153,7 +1340,7 @@ docker_compose_down() { } domain_setup_manual() { - ns_external_port=$(dotenv-tool -r get -f $ENV_FILE_DEP "NS_PORT") + ns_external_port=$(dotenv-tool -r get -f "$ENV_FILE_DEP" "NS_PORT") whiptail --title "Ustaw domenę" --msgbox "Aby Nightscout był widoczny z internetu ustaw subdomenę:\n\n${uni_bullet}otwórz nową zakładkę w przeglądarce,\n${uni_bullet}wejdź do panelu administracyjnego swojego Mikr.us-a,\n${uni_bullet}otwórz sekcję [Subdomeny], pod adresem:\n\n${uni_bullet_pad} https://mikr.us/panel/?a=domain\n\n${uni_bullet}w pole nazwy wpisz dowolną własną nazwę\n${uni_bullet_pad}(tylko małe litery i cyfry, max. 12 znaków)\n${uni_bullet}w pole numer portu wpisz:\n${uni_bullet_pad}\n $ns_external_port\n\n${uni_bullet}kliknij [Dodaj subdomenę] i poczekaj do kilku minut" 22 75 } @@ -1170,7 +1357,7 @@ domain_setup() { return fi - ns_external_port=$(dotenv-tool -r get -f $ENV_FILE_DEP "NS_PORT") + ns_external_port=$(dotenv-tool -r get -f "$ENV_FILE_DEP" "NS_PORT") whiptail --title "Ustaw subdomenę" --msgbox "Aby Nightscout był widoczny z internetu ustaw adres - subdomenę:\n\n [wybierz].ns.techdiab.pl\n\nWybrany początek subdomeny powinien:\n${uni_bullet}mieć długość od 4 do 12 znaków\n${uni_bullet}zaczynać się z małej litery,\n${uni_bullet}może składać się z małych liter i cyfr\n${uni_bullet}być unikalny, charakterystyczny i łatwa do zapamiętania" 16 75 while :; do @@ -1184,7 +1371,7 @@ domain_setup() { if [[ "$SUBDOMAIN" =~ ^[a-z][a-z0-9]{3,11}$ ]]; then - if printf "%s" "$SUBDOMAIN" | grep -f "$PROFANITY_DB_FILE" >>$LOGTO 2>&1; then + if printf "%s" "$SUBDOMAIN" | grep -f "$PROFANITY_DB_FILE" >>"$LOGTO" 2>&1; then okdlg "$uni_excl Nieprawidłowa subdomena $uni_excl" \ "Podana wartość:" \ "${NL}$SUBDOMAIN" \ @@ -1194,7 +1381,7 @@ domain_setup() { continue fi - if printf "%s" "$SUBDOMAIN" | grep -xf "$RESERVED_DB_FILE" >>$LOGTO 2>&1; then + if printf "%s" "$SUBDOMAIN" | grep -xf "$RESERVED_DB_FILE" >>"$LOGTO" 2>&1; then okdlg "$uni_excl Nieprawidłowa subdomena $uni_excl" \ "Podana wartość:" \ "${NL}$SUBDOMAIN" \ @@ -1225,7 +1412,7 @@ domain_setup() { fi local MHOST=$(hostname) - local APISEC=$(dotenv-tool -r get -f $ENV_FILE_ADMIN "MIKRUS_APIKEY") + local APISEC=$(dotenv-tool -r get -f "$ENV_FILE_ADMIN" "MIKRUS_APIKEY") ohai "Rejestrowanie subdomeny $SUBDOMAIN.ns.techdiab.pl" local REGSTATUS=$(curl -sd "srv=$MHOST&key=$APISEC&domain=$SUBDOMAIN.ns.techdiab.pl" https://api.mikr.us/domain) @@ -1264,7 +1451,7 @@ get_watchdog_age_string() { local curr_time=$(date -u +"%Y-%m-%dT%H:%M:%SZ") if [[ -f $WATCHDOG_TIME_FILE ]]; then - last_time=$(cat $WATCHDOG_TIME_FILE) + last_time=$(cat "$WATCHDOG_TIME_FILE") local status_ago=$(dateutils.ddiff "$last_time" "$curr_time" -f '%Mmin. %Ssek.') echo "$last_time ($status_ago temu)" else @@ -1278,11 +1465,11 @@ get_watchdog_status_code() { local status="unknown" if [[ -f $WATCHDOG_TIME_FILE ]]; then - last_time=$(cat $WATCHDOG_TIME_FILE) + last_time=$(cat "$WATCHDOG_TIME_FILE") fi if [[ -f $WATCHDOG_STATUS_FILE ]]; then - status=$(cat $WATCHDOG_STATUS_FILE) + status=$(cat "$WATCHDOG_STATUS_FILE") fi local status_ago=$(dateutils.ddiff "$curr_time" "$last_time" -f '%S') @@ -1300,11 +1487,11 @@ get_watchdog_status_code_live() { local status="unknown" if [[ -f $WATCHDOG_TIME_FILE ]]; then - last_time=$(cat $WATCHDOG_TIME_FILE) + last_time=$(cat "$WATCHDOG_TIME_FILE") fi if [[ -f $WATCHDOG_STATUS_FILE ]]; then - status=$(cat $WATCHDOG_STATUS_FILE) + status=$(cat "$WATCHDOG_STATUS_FILE") fi local status_ago=$(dateutils.ddiff "$curr_time" "$last_time" -f '%S') @@ -1353,7 +1540,13 @@ get_watchdog_status_code_live() { if [ "$NS_STATUS" = "restarting" ] || [ "$DB_STATUS" = "restarting" ]; then status="awaiting" else - status="not_running" + local logSample=$(timeout -k 15 10 docker logs ns-server --tail "10" 2>&1) + local regexSample='Cannot connect to the Docker daemon' + if [[ "$logSample" =~ $regexSample ]]; then + status="docker_down" + else + status="not_running" + fi fi fi @@ -1393,6 +1586,9 @@ get_watchdog_status() { "crashed") printf "\U1F4A5 awaria NS" ;; + "docker_down") + printf "\U1F4A5 awaria Dockera" + ;; esac } @@ -1400,13 +1596,13 @@ get_watchdog_status() { show_watchdog_logs() { local col=$((COLUMNS - 10)) local rws=$((LINES - 3)) - if [ $col -gt 120 ]; then + if [ "$col" -gt 120 ]; then col=160 fi - if [ $col -lt 60 ]; then + if [ "$col" -lt 60 ]; then col=60 fi - if [ $rws -lt 12 ]; then + if [ "$rws" -lt 12 ]; then rws=12 fi @@ -1430,10 +1626,23 @@ show_watchdog_logs() { fi } >"$tmpfile" - whiptail --title "Logi Watchdoga" --scrolltext --textbox "$tmpfile" $rws $col + whiptail --title "Logi Watchdoga" --scrolltext --textbox "$tmpfile" "$rws" "$col" rm "$tmpfile" } +get_events_status() { + local count="$(event_count)" + if (( count == 0 )); then + printf "\U2728 brak zdarzeń" + elif (( count == 1 )); then + printf "\U1F4C5 jedno zdarzenie" + elif (( (count % 10) > 1)) && (( (count % 10) < 5)); then + printf "\U1F4C5 %s zdarzenia" "$count" + else + printf "\U1F4C5 %s zdarzeń" "$count" + fi +} + get_container_status() { local ID=$(docker ps -a --no-trunc --filter name="^$1$" --format '{{ .ID }}') if [[ "$ID" =~ [0-9a-fA-F]{12,} ]]; then @@ -1477,13 +1686,13 @@ get_container_status_code() { show_logs() { local col=$((COLUMNS - 10)) local rws=$((LINES - 4)) - if [ $col -gt 120 ]; then + if [ "$col" -gt 120 ]; then col=160 fi - if [ $col -lt 60 ]; then + if [ "$col" -lt 60 ]; then col=60 fi - if [ $rws -lt 12 ]; then + if [ "$rws" -lt 12 ]; then rws=12 fi @@ -1491,18 +1700,19 @@ show_logs() { if [ -n "$ID" ]; then local tmpfile=$(mktemp) docker logs "$ID" 2>&1 | tail $((rws * -6)) | sed 's/\x1B\[[0-9;]\{1,\}[A-Za-z]//g' >"$tmpfile" - whiptail --title "Logi $2" --scrolltext --textbox "$tmpfile" $rws $col + whiptail --title "Logi $2" --scrolltext --textbox "$tmpfile" "$rws" "$col" rm "$tmpfile" fi } status_menu() { while :; do - local CHOICE=$(whiptail --title "Status kontenerów" --menu "\n Aktualizacja: kontenery na żywo, watchdog co 5 minut\n\n Wybierz pozycję aby zobaczyć logi:\n" 17 60 5 \ + local CHOICE=$(whiptail --title "Status kontenerów" --menu "\n Aktualizacja: kontenery na żywo, watchdog co 5 minut\n\n Wybierz pozycję aby zobaczyć logi:\n" 18 60 6 \ "1)" " Nightscout: $(get_container_status 'ns-server')" \ "2)" " Baza danych: $(get_container_status 'ns-database')" \ "3)" " Backup: $(get_container_status 'ns-backup')" \ "4)" " Watchdog: $(get_watchdog_status "$(get_watchdog_status_code)" "$uni_watchdog_ok")" \ + "5)" " Zdarzenia: $(get_events_status)" \ "M)" "Powrót do menu" \ --ok-button="Zobacz logi" --cancel-button="$uni_back" \ 3>&2 2>&1 1>&3) @@ -1520,6 +1730,10 @@ status_menu() { "4)") show_watchdog_logs ;; + "5)") + okdlg "Zdarzenia" \ + "$(pad_multiline "$(event_list)")" + ;; "M)") break ;; @@ -1536,7 +1750,7 @@ version_menu() { while :; do - local ns_tag=$(dotenv-tool -r get -f $ENV_FILE_DEP "NS_NIGHTSCOUT_TAG") + local ns_tag=$(dotenv-tool -r get -f "$ENV_FILE_DEP" "NS_NIGHTSCOUT_TAG") local versions=() while read -r line; do @@ -1580,9 +1794,10 @@ version_menu() { whiptail --title "Zmienić wersję Nightscout?" --yesno --defaultno "Czy na pewno chcesz zmienić wersję z: $ns_tag na: $CHOICE?\n\n${uni_bullet}dane i konfiguracja NIE SĄ usuwane\n${uni_bullet}wersję można łatwo zmienić ponownie\n${uni_bullet}dane w bazie danych mogą ulec zmianie i NIE BYĆ kompatybilne" --yes-button "$uni_confirm_ch" --no-button "$uni_resign" 13 73 if ! [ $? -eq 1 ]; then + event_mark "change_ns_version" docker_compose_down ohai "Changing Nightscout container tag from: $ns_tag to: $CHOICE" - dotenv-tool -pmr -i $ENV_FILE_DEP -- "NS_NIGHTSCOUT_TAG=$CHOICE" + dotenv-tool -pmr -i "$ENV_FILE_DEP" -- "NS_NIGHTSCOUT_TAG=$CHOICE" docker_compose_update whiptail --title "Zmieniono wersję Nightscout" --msgbox "$(center_multiline 65 \ "Zmieniono wersję Nightscout na: $CHOICE" \ @@ -1601,26 +1816,56 @@ version_menu() { do_cleanup_sys() { ohai "Sprzątanie dziennik systemowego..." - journalctl --vacuum-size=50M >>$LOGTO 2>&1 + event_mark "cleanup" + journalctl --vacuum-size=50M >>"$LOGTO" 2>&1 ohai "Czyszczenie systemu apt..." msgnote "Ta operacja może TROCHĘ potrwać (od kilku do kilkudziesięciu minut...)" - apt-get -y autoremove >>$LOGTO 2>&1 && apt-get -y clean >>$LOGTO 2>&1 + apt-get -y autoremove >>"$LOGTO" 2>&1 && apt-get -y clean >>"$LOGTO" 2>&1 msgcheck "Czyszczenie dziennika i apt zakończono" } do_cleanup_docker() { ohai "Usuwanie nieużywanych obrazów Dockera..." + event_mark "cleanup" msgnote "Ta operacja może TROCHĘ potrwać (do kilku minut...)" - docker image prune -af >>$LOGTO 2>&1 + docker image prune -af >>"$LOGTO" 2>&1 msgcheck "Czyszczenie Dockera zakończono" } do_cleanup_db() { ohai "Usuwanie kopii zapasowych bazy danych..." + event_mark "cleanup" find /srv/nightscout/data/dbbackup ! -type d -delete msgcheck "Czyszczenie kopii zapasowych zakończono" } +do_cleanup_container_logs() { + ohai "Zatrzymywanie kontenerów..." + event_mark "cleanup" + docker stop 'ns-server' + docker stop 'ns-database' + docker stop 'ns-backup' + ohai "Usuwanie logów kontenerów..." + truncate -s 0 "$(docker inspect --format='{{.LogPath}}' 'ns-server')" + truncate -s 0 "$(docker inspect --format='{{.LogPath}}' 'ns-database')" + truncate -s 0 "$(docker inspect --format='{{.LogPath}}' 'ns-backup')" + ohai "Ponowne uruchamianie kontenerów..." + docker start 'ns-server' + docker start 'ns-database' + docker start 'ns-backup' + msgok "Logi usunięte" +} + +prompt_cleanup_container_logs() { + yesnodlg "Usunąć logi kontenerów?" "$uni_delete" "$uni_leave_logs" \ + "Czy chcesz usunąć logi kontenerów nightscout i bazy?" \ + "${TL}Jeśli Twój serwer działa poprawnie," \ + "${NL}- możesz spokojnie usunąć logi." \ + "${TL}Jeśli masz problem z serwerem - zostaw logi!" \ + "${NL}- logi mogą być niezbędne do diagnostyki" \ + "${TL}(ta operacja uruchomi ponownie kontenery)" +} + cleanup_menu() { while :; do @@ -1649,11 +1894,12 @@ cleanup_menu() { local CHOICE=$(whiptail --title "Sprzątanie" --menu \ "${statusTitle/=/%}" \ - 16 50 5 \ + 17 50 6 \ "A)" "Posprzątaj wszystko" \ "S)" "Posprzątaj zasoby systemowe" \ "D)" "Usuń nieużywane obrazy Dockera" \ "B)" "Usuń kopie zapasowe bazy danych" \ + "L)" "Usuń logi kontenerów" \ "M)" "Powrót do menu" \ --ok-button="Wybierz" --cancel-button="$uni_back" \ 3>&2 2>&1 1>&3) @@ -1668,9 +1914,17 @@ cleanup_menu() { "${NL} ${uni_bullet}kopie zapasowe bazy danych")" \ "${TL}(ta operacja może potrwać od kilku do kilkudziesięciu minut)" if ! [ $? -eq 1 ]; then - do_cleanup_sys - do_cleanup_docker - do_cleanup_db + prompt_cleanup_container_logs + if ! [ $? -eq 1 ]; then + do_cleanup_container_logs + do_cleanup_sys + do_cleanup_docker + do_cleanup_db + else + do_cleanup_sys + do_cleanup_docker + do_cleanup_db + fi fi ;; "S)") @@ -1697,6 +1951,12 @@ cleanup_menu() { do_cleanup_db fi ;; + "L)") + prompt_cleanup_container_logs + if ! [ $? -eq 1 ]; then + do_cleanup_container_logs + fi + ;; "M)") break ;; @@ -1720,16 +1980,19 @@ update_menu() { case $CHOICE in "S)") ohai "Updating package list" + event_mark "update_system" dialog --title " Aktualizacja systemu " --infobox "\n Pobieranie listy pakietów\n ..... Proszę czekać ....." 6 33 - apt-get -yq update >>$LOGTO 2>&1 + apt-get -yq update >>"$LOGTO" 2>&1 ohai "Upgrading system" dialog --title " Aktualizacja systemu " --infobox "\n Instalowanie pakietów\n ... Proszę czekać ..." 6 33 - apt-get -yq upgrade >>$LOGTO 2>&1 + apt-get -yq upgrade >>"$LOGTO" 2>&1 ;; "N)") + event_mark "update_tool" update_if_needed "Wszystkie pliki narzędzia są aktualne" ;; "K)") + event_mark "update_containers" docker_compose_down docker_compose_update ;; @@ -1747,7 +2010,7 @@ uninstall_menu() { while :; do local extraMenu=() extraMenu+=("A)" "Ustaw adres strony (subdomenę)") - local ns_tag=$(dotenv-tool -r get -f $ENV_FILE_DEP "NS_NIGHTSCOUT_TAG") + local ns_tag=$(dotenv-tool -r get -f "$ENV_FILE_DEP" "NS_NIGHTSCOUT_TAG") local CHOICE=$(whiptail --title "Zmień lub odinstaluj Nightscout" --menu "\n" 17 70 8 \ "${extraMenu[@]}" \ "W)" "Zmień wersję Nightscouta (bieżąca: $ns_tag)" \ @@ -1776,7 +2039,8 @@ uninstall_menu() { else whiptail --title "Edycja ustawień Nightscout" --yesno "Za chwilę otworzę plik konfiguracji Nightscout w edytorze NANO\n\nWskazówki co do obsługi edytora:\n${uni_bullet}Aby ZAPISAĆ zmiany naciśnij Ctrl+O\n${uni_bullet}Aby ZAKOŃCZYĆ edycję naciśnij Ctrl+X\n\n $(printf "\U26A0") Edycja spowoduje też restart i aktualizację kontenerów $(printf "\U26A0")" --yes-button "$uni_confirm_ed" --no-button "$uni_resign" 15 68 if ! [ $? -eq 1 ]; then - nano $ENV_FILE_NS + event_mark "edit_env_manual" + nano "$ENV_FILE_NS" docker_compose_down docker_compose_update fi @@ -1785,6 +2049,7 @@ uninstall_menu() { "K)") whiptail --title "Usunąć kontenery?" --yesno --defaultno "Czy na pewno chcesz usunąć kontenery powiązane z Nightscout?\n\n${uni_bullet}dane i konfiguracja NIE SĄ usuwane\n${uni_bullet}kontenery można łatwo odzyskać (opcja Aktualizuj kontenery)" --yes-button "$uni_confirm_del" --no-button "$uni_resign" 11 73 if ! [ $? -eq 1 ]; then + event_mark "remove_containers" docker_compose_down fi ;; @@ -1794,6 +2059,7 @@ uninstall_menu() { docker_compose_down dialog --title " Czyszczenie bazy danych " --infobox "\n Usuwanie plików bazy\n ... Proszę czekać ..." 6 32 rm -r "${MONGO_DB_DIR:?}/data" + event_mark "remove_db_data" docker_compose_update fi ;; @@ -1803,6 +2069,7 @@ uninstall_menu() { docker_compose_down dialog --title " Czyszczenie bazy danych" --infobox "\n Usuwanie plików bazy\n ... Proszę czekać ..." 6 32 rm -r "${MONGO_DB_DIR:?}/data" + event_mark "remove_all_data" dialog --title " Czyszczenie konfiguracji" --infobox "\n Usuwanie konfiguracji\n ... Proszę czekać ..." 6 32 rm -r "${CONFIG_ROOT_DIR:?}" whiptail --title "Usunięto dane użytkownika" --msgbox "$(center_multiline 65 \ @@ -1824,6 +2091,7 @@ uninstall_menu() { rm "$TOOL_LINK" rm -r "${NIGHTSCOUT_ROOT_DIR:?}/tools" rm -r "${NIGHTSCOUT_ROOT_DIR:?}/updates" + event_mark "uninstall" whiptail --title "Odinstalowano" --msgbox "$(center_multiline 65 \ "Odinstalowano Nightscout z Mikr.us-a" \ "${TL}Aby ponownie zainstalować, postępuj według instrukcji na stronie:" \ @@ -1845,7 +2113,7 @@ uninstall_menu() { get_td_domain() { local MHOST=$(hostname) - local APIKEY=$(dotenv-tool -r get -f $ENV_FILE_ADMIN "MIKRUS_APIKEY") + local APIKEY=$(dotenv-tool -r get -f "$ENV_FILE_ADMIN" "MIKRUS_APIKEY") curl -sd "srv=$MHOST&key=$APIKEY" https://api.mikr.us/domain | jq -r ".[].name" | grep ".ns.techdiab.pl" | head -n 1 } @@ -1870,12 +2138,12 @@ gather_diagnostics() { ohai "Zbieranie diagnostyki" local domain=$(get_td_domain) - local ns_tag=$(dotenv-tool -r get -f $ENV_FILE_DEP "NS_NIGHTSCOUT_TAG") + local ns_tag=$(dotenv-tool -r get -f "$ENV_FILE_DEP" "NS_NIGHTSCOUT_TAG") local mikrus_h=$(hostname) local LOG_DIVIDER="=======================================================" - rm -f $SUPPORT_LOG + rm -f "$SUPPORT_LOG" rm -f "$SUPPORT_LOG.gz" rm -f "$SUPPORT_LOG.gz.asc" @@ -1885,7 +2153,7 @@ gather_diagnostics() { echo " domena : $domain" echo " wersja nightscout : $ns_tag" echo " wersja nightscout-tool : $SCRIPT_VERSION ($SCRIPT_BUILD_TIME) $UPDATE_CHANNEL" - } >$SUPPORT_LOG + } >"$SUPPORT_LOG" ohai "Zbieranie statusu usług" @@ -1897,7 +2165,7 @@ gather_diagnostics() { echo " Baza danych: $(get_container_status 'ns-database')" echo " Backup: $(get_container_status 'ns-backup')" echo " Watchdog: $(get_watchdog_status "$(get_watchdog_status_code)" "$uni_watchdog_ok")" - } >>$SUPPORT_LOG + } >>"$SUPPORT_LOG" local spaceInfo=$(get_space_info) local remainingTxt=$(echo "$spaceInfo" | awk '{print $3}' | numfmt --to iec-i --suffix=B) @@ -1910,17 +2178,25 @@ gather_diagnostics() { echo "$LOG_DIVIDER" echo " Dostępne: ${remainingTxt}" echo " Zajęte: ${percTxt} (z ${totalTxt})" - } >>$SUPPORT_LOG + } >>"$SUPPORT_LOG" - ohai "Zbieranie logów watchdoga" + ohai "Zbieranie zdarzeń" + { + echo "$LOG_DIVIDER" + echo " Zdarzenia" + echo "$LOG_DIVIDER" + event_list + } >>"$SUPPORT_LOG" + + ohai "Zbieranie logów watchdoga" if [[ -f $WATCHDOG_LOG_FILE ]]; then { echo "$LOG_DIVIDER" echo " Watchdog log" echo "$LOG_DIVIDER" - timeout -k 15 10 cat $WATCHDOG_LOG_FILE - } >>$SUPPORT_LOG + timeout -k 15 10 cat "$WATCHDOG_LOG_FILE" + } >>"$SUPPORT_LOG" fi if [[ -f $WATCHDOG_FAILURES_FILE ]]; then @@ -1928,8 +2204,8 @@ gather_diagnostics() { echo "$LOG_DIVIDER" echo " Watchdog failures log" echo "$LOG_DIVIDER" - timeout -k 15 10 cat $WATCHDOG_FAILURES_FILE - } >>$SUPPORT_LOG + timeout -k 15 10 cat "$WATCHDOG_FAILURES_FILE" + } >>"$SUPPORT_LOG" fi ohai "Zbieranie logów usług" @@ -1938,18 +2214,18 @@ gather_diagnostics() { echo "$LOG_DIVIDER" echo " Nightscout log" echo "$LOG_DIVIDER" - timeout -k 15 10 docker logs ns-server --tail "$maxNsLogs" >>$SUPPORT_LOG 2>&1 + timeout -k 15 10 docker logs ns-server --tail "$maxNsLogs" >>"$SUPPORT_LOG" 2>&1 echo "$LOG_DIVIDER" echo " MongoDB database log" echo "$LOG_DIVIDER" - timeout -k 15 10 docker logs ns-database --tail "$maxDbLogs" >>$SUPPORT_LOG 2>&1 - } >>$SUPPORT_LOG + timeout -k 15 10 docker logs ns-database --tail "$maxDbLogs" >>"$SUPPORT_LOG" 2>&1 + } >>"$SUPPORT_LOG" ohai "Kompresowanie i szyfrowanie raportu" - gzip -9 $SUPPORT_LOG + gzip -9 "$SUPPORT_LOG" - local logkey=$(<$LOG_ENCRYPTION_KEY_FILE) + local logkey=$(<"$LOG_ENCRYPTION_KEY_FILE") gpg --passphrase "$logkey" --batch --quiet --yes -a -c "$SUPPORT_LOG.gz" } @@ -1982,7 +2258,7 @@ send_diagnostics() { setup_security - LOG_KEY=$(<$LOG_ENCRYPTION_KEY_FILE) + LOG_KEY=$(<"$LOG_ENCRYPTION_KEY_FILE") yesnodlg "Wysyłać diagnostykę?" \ "$uni_send" "$uni_resign" \ @@ -2046,7 +2322,7 @@ send_diagnostics() { main_menu() { while :; do - local ns_tag=$(dotenv-tool -r get -f $ENV_FILE_DEP "NS_NIGHTSCOUT_TAG") + local ns_tag=$(dotenv-tool -r get -f "$ENV_FILE_DEP" "NS_NIGHTSCOUT_TAG") local quickStatus=$(center_text "Strona Nightscout: $(get_watchdog_status "$(get_watchdog_status_code_live)" "$uni_ns_ok")" 55) local quickVersion=$(center_text "Wersja: $ns_tag" 55) local quickDomain=$(center_text "Domena: $(get_domain_status 'ns-server')" 55) @@ -2068,8 +2344,8 @@ main_menu() { status_menu ;; "P)") - local ns_external_port=$(dotenv-tool -r get -f $ENV_FILE_DEP "NS_PORT") - local ns_api_secret=$(dotenv-tool -r get -f $ENV_FILE_NS "API_SECRET") + local ns_external_port=$(dotenv-tool -r get -f "$ENV_FILE_DEP" "NS_PORT") + local ns_api_secret=$(dotenv-tool -r get -f "$ENV_FILE_NS" "API_SECRET") whiptail --title "Podgląd konfiguracji Nightscout" --msgbox \ "\n Port usługi Nightscout: $ns_external_port\n API_SECRET: $ns_api_secret" \ 10 60 @@ -2124,10 +2400,12 @@ install_or_menu() { if [ "$freshInstall" -gt 0 ]; then ohai "Instalowanie Nightscout..." + event_mark "install_start" docker_compose_update setup_firewall_for_ns domain_setup # admin_panel_promo + event_mark "install_end" setup_done else main_menu @@ -2140,74 +2418,113 @@ install_or_menu() { free_space_check() { lastTimeSpaceInfo=$(get_space_info) - + local remainingB=$(echo "$lastTimeSpaceInfo" | awk '{print $3}') local remainingTxt=$(echo "$lastTimeSpaceInfo" | awk '{print $3}' | numfmt --to iec-i --suffix=B) - if ((remainingB < DISK_LOW_WARNING)); then - if ((remainingB < DISK_CRITICAL_WARNING)); then - local lastCalled=$(get_since_last_time "disk_critical") - local domain=$(get_td_domain) - if ((lastCalled == -1)) || ((lastCalled > DISK_CRITICAL_MAIL)); then - set_last_time "disk_critical" - { - echo "Na twoim serwerze mikr.us z Nightscoutem (https://$domain) zostało krytycznie mało miejsca (${remainingTxt})!" - echo " " - echo "Tak mała ilość miejsca nie pozwala serwerowi na stabilne działanie!" - echo "🚨PILNIE🚨 posprzątaj na serwerze, aby to zrobić możesz:" - echo " " - echo "1. Usunąć stare statusy i wpisy z poziomu strony Nightscout:" - echo " - wejdź do hamburger menu strony Nightscout i wybierz: 【 Narzędzia administratora 】- wymaga zalogowania" - echo " to powinno otwórzyć adres: https://${domain}/admin" - echo " - w polach tekstowych poustawiaj ile dni historii chcesz zachować, i w odpowiednich sekcjach kliknij:" - echo " 【 Usuń stare dokumenty 】" - echo " " - echo "2. Posprzątać nieużywane pliki na serwerze mikr.us:" - echo " - zaloguj się na swój mikr.us do panelu administracyjnego, przejdź do WebSSH" - echo " https://mikr.us/panel/?a=webssh" - echo " - zaloguj się, uruchom narzędzie komendą: nightscout-tool" - echo " - wybierz: 【 C) Sprztąj... 】" - echo " - wybierz: 【 A) Posprzątaj wszystko 】 i potwierdź 【 Tak 】" - echo " - cierpliwie poczekaj, po sprzątaniu narzędzie pokaże ile miejsca zwolniono" - } | pusher "🚨_Krytycznie_mało_miejsca_na_Twoim_serwerze_Nightscout!" - echo "Free space on server: CRITICALLY LOW (${remainingTxt}) - sending email to user" - else - echo "Free space on server: CRITICALLY LOW (${remainingTxt}) - user already notified" - fi - else - local lastCalled=$(get_since_last_time "disk_warning") - local domain=$(get_td_domain) - if ((lastCalled == -1)) || ((lastCalled > DISK_LOW_MAIL)); then - set_last_time "disk_warning" - { - echo "Na twoim serwerze mikr.us z Nightscout-em (https://$domain) powoli kończy się miejsce (${remainingTxt})!" - echo " " - echo "🧹 W wolnej chwili posprzątaj na serwerze, aby to zrobić możesz:" - echo " " - echo "1. Usunąć stare statusy i wpisy z poziomu strony Nightscout:" - echo " - wejdź do hamburger menu strony Nightscout i wybierz:【 Narzędzia administratora 】- wymaga zalogowania" - echo " to powinno otwórzyć adres: https://${domain}/admin" - echo " - w polach tekstowych poustawiaj ile dni historii chcesz zachować, i w odpowiednich sekcjach kliknij:" - echo " 【 Usuń stare dokumenty 】" - echo " " - echo "2. Posprzątać nieużywane pliki na serwerze mikr.us:" - echo " - zaloguj się na swój mikr.us do panelu administracyjnego, przejdź do WebSSH" - echo " https://mikr.us/panel/?a=webssh" - echo " - zaloguj się, uruchom narzędzie komendą: nightscout-tool" - echo " - wybierz: 【 C) Sprztąj... 】" - echo " - wybierz: 【 A) Posprzątaj wszystko 】 i potwierdź 【 Tak 】" - echo " - cierpliwie poczekaj, po sprzątaniu narzędzie pokaże ile miejsca zwolniono" - } | pusher "🧹_Powoli_kończy_sie_miejsce_na_Twoim_serwerze_Nightscout!" - echo "Free space on server: LOW (${remainingTxt}) - sending email to user" - else - echo "Free space on server: LOW (${remainingTxt}) - user already notified" - fi - fi - else - clear_last_time "disk_critical" - clear_last_time "disk_warning" - echo "Free space on server: OK (${remainingTxt})" - fi + if ((remainingB < DISK_LOW_WARNING)); then + if ((remainingB < DISK_CRITICAL_WARNING)); then + local lastCalled=$(get_since_last_time "disk_critical") + local domain=$(get_td_domain) + if ((lastCalled == -1)) || ((lastCalled > DISK_CRITICAL_MAIL)); then + set_last_time "disk_critical" + { + echo "Na twoim serwerze mikr.us z Nightscoutem (https://$domain) zostało krytycznie mało miejsca (${remainingTxt})!" + echo " " + echo "Tak mała ilość miejsca nie pozwala serwerowi na stabilne działanie!" + echo "🚨PILNIE🚨 posprzątaj na serwerze, aby to zrobić możesz:" + echo " " + echo "1. Usunąć stare statusy i wpisy z poziomu strony Nightscout:" + echo " - wejdź do hamburger menu strony Nightscout i wybierz: 【 Narzędzia administratora 】- wymaga zalogowania" + echo " to powinno otwórzyć adres: https://${domain}/admin" + echo " - w polach tekstowych poustawiaj ile dni historii chcesz zachować, i w odpowiednich sekcjach kliknij:" + echo " 【 Usuń stare dokumenty 】" + echo " " + echo "2. Posprzątać nieużywane pliki na serwerze mikr.us:" + echo " - zaloguj się na swój mikr.us do panelu administracyjnego, przejdź do WebSSH" + echo " https://mikr.us/panel/?a=webssh" + echo " - zaloguj się, uruchom narzędzie komendą: nightscout-tool" + echo " - wybierz: 【 C) Sprztąj... 】" + echo " - wybierz: 【 A) Posprzątaj wszystko 】 i potwierdź 【 Tak 】" + echo " - cierpliwie poczekaj, po sprzątaniu narzędzie pokaże ile miejsca zwolniono" + } | pusher "🚨_Krytycznie_mało_miejsca_na_Twoim_serwerze_Nightscout!" + echo "Free space on server: CRITICALLY LOW (${remainingTxt}) - sending email to user" + else + echo "Free space on server: CRITICALLY LOW (${remainingTxt}) - user already notified" + fi + else + local lastCalled=$(get_since_last_time "disk_warning") + local domain=$(get_td_domain) + if ((lastCalled == -1)) || ((lastCalled > DISK_LOW_MAIL)); then + set_last_time "disk_warning" + { + echo "Na twoim serwerze mikr.us z Nightscout-em (https://$domain) powoli kończy się miejsce (${remainingTxt})!" + echo " " + echo "🧹 W wolnej chwili posprzątaj na serwerze, aby to zrobić możesz:" + echo " " + echo "1. Usunąć stare statusy i wpisy z poziomu strony Nightscout:" + echo " - wejdź do hamburger menu strony Nightscout i wybierz:【 Narzędzia administratora 】- wymaga zalogowania" + echo " to powinno otwórzyć adres: https://${domain}/admin" + echo " - w polach tekstowych poustawiaj ile dni historii chcesz zachować, i w odpowiednich sekcjach kliknij:" + echo " 【 Usuń stare dokumenty 】" + echo " " + echo "2. Posprzątać nieużywane pliki na serwerze mikr.us:" + echo " - zaloguj się na swój mikr.us do panelu administracyjnego, przejdź do WebSSH" + echo " https://mikr.us/panel/?a=webssh" + echo " - zaloguj się, uruchom narzędzie komendą: nightscout-tool" + echo " - wybierz: 【 C) Sprztąj... 】" + echo " - wybierz: 【 A) Posprzątaj wszystko 】 i potwierdź 【 Tak 】" + echo " - cierpliwie poczekaj, po sprzątaniu narzędzie pokaże ile miejsca zwolniono" + } | pusher "🧹_Powoli_kończy_sie_miejsce_na_Twoim_serwerze_Nightscout!" + echo "Free space on server: LOW (${remainingTxt}) - sending email to user" + else + echo "Free space on server: LOW (${remainingTxt}) - user already notified" + fi + fi + else + clear_last_time "disk_critical" + clear_last_time "disk_warning" + echo "Free space on server: OK (${remainingTxt})" + fi +} + +mail_restart_needed() { + local whyRestart="$1" + local mikrusSerwer=$(hostname) + { + echo "🛟 Twój serwer mikr.us z Nightscoutem potrzebuje restartu!" + echo " " + echo "🐕 Watchdog wykrył awarię której nie jest w stanie automatycznie naprawić:" + echo "$whyRestart" + echo " " + echo "Potrzebna będzie Twoja pomoc z ręcznym restartem serwera:" + echo " " + echo "1. Zaloguj się do panelu administracyjnego mikrusa" + echo " https://mikr.us/panel/" + echo " " + echo "2. Znajdź kafelek z nazwą serwera (${mikrusSerwer}) i kliknij na przycisk pod nim:" + echo " 【 Restart 】" + echo " " + echo "3. Potwierdź naciskając przycisk:" + echo " 【 Poproszę o restart VPSa 】" + echo " " + echo "==========================================================" + echo " " + echo "⏳ Restart serwera potrwa kilka minut, kolejne kilka minut potrwa uruchomienie serwera Nightscout" + echo "Jeśli po kilkunastu minutach serwer nie zacznie działać poprawnie:" + echo "Zaloguj się do panelu mikr.us-a, zaloguj się do WebSSH i w nightscout-tool sprawdź:" + echo "- czy kontenery są uruchomione - ich status i logi" + echo "- czy jest dosyć wolnego miejsca" + echo "W razie potrzeby - 🔄 zrestartuj kontenery i uruchom 🧹 sprzątanie (ale NIE usuwaj logów!)." + echo " " + echo "==========================================================" + echo " " + echo "Jeśli to nie pomoże, poszukaj wsparcia na grupie Technologie Diabetyka" + echo " 🙋 https://www.facebook.com/groups/techdiab" + echo "i - po uzgodnieniu!!! - wyślij diagnostykę do autora skryptu:" + echo " 📜 https://t1d.dzienia.pl/nightscout_mikrus_tutorial/stabilna/5.troubleshooting/#wysyanie-diagnostyki" + echo " " + } | pusher "🛟_Twoj_serwer_Nightscout_potrzebuje_ręcznego_restartu!" } watchdog_check() { @@ -2220,14 +2537,14 @@ watchdog_check() { if [[ -f $WATCHDOG_TIME_FILE ]]; then echo "Found $WATCHDOG_TIME_FILE" - WATCHDOG_LAST_TIME=$(cat $WATCHDOG_TIME_FILE) + WATCHDOG_LAST_TIME=$(cat "$WATCHDOG_TIME_FILE") else echo "First watchdog run" fi if [[ -f $WATCHDOG_STATUS_FILE ]]; then echo "Found $WATCHDOG_STATUS_FILE" - WATCHDOG_LAST_STATUS=$(cat $WATCHDOG_STATUS_FILE) + WATCHDOG_LAST_STATUS=$(cat "$WATCHDOG_STATUS_FILE") fi local STATUS_AGO=$(dateutils.ddiff "$WATCHDOG_TIME" "$WATCHDOG_LAST_TIME" -f '%S') @@ -2237,7 +2554,7 @@ watchdog_check() { WATCHDOG_LAST_STATUS="unknown" fi - free_space_check + free_space_check local NS_STATUS=$(get_container_status_code 'ns-server') local DB_STATUS=$(get_container_status_code 'ns-database') @@ -2247,6 +2564,10 @@ watchdog_check() { echo "Database container: $DB_STATUS" if [ "$COMBINED_STATUS" = "running running" ]; then + + clear_last_time "docker_down" + clear_last_time "server_restart_needed" + echo "Will check page contents" local domain=$(get_td_domain) @@ -2265,6 +2586,7 @@ watchdog_check() { echo "Nightscout crash detected" WATCHDOG_STATUS="restart" if [ "$WATCHDOG_LAST_STATUS" == "restart_failed" ]; then + event_mark "restart_both" echo "Restarting DB first..." docker restart 'ns-database' echo "Then, restarting Nightscout..." @@ -2273,6 +2595,7 @@ watchdog_check() { WATCHDOG_STATUS="full_restart" else if [ "$WATCHDOG_LAST_STATUS" != "restart" ]; then + event_mark "restart_ns" echo "Restarting only Nightscout..." docker restart 'ns-server' echo "...done" @@ -2309,37 +2632,58 @@ watchdog_check() { WATCHDOG_STATUS="awaiting" else WATCHDOG_STATUS="not_running" + + local logSample=$(timeout -k 15 10 docker logs ns-server --tail "10" 2>&1) + local regexSample='Cannot connect to the Docker daemon' + if [[ "$logSample" =~ $regexSample ]]; then + WATCHDOG_STATUS="docker_down" + if [ "$WATCHDOG_LAST_STATUS" != "docker_down" ]; then + echo "Cannot connect to Docker, will restart service..." + set_last_time "docker_down" + sudo systemctl restart docker + else + echo "Cannot connect to Docker, and service cannot be restarted" + local lastCalled=$(get_since_last_time "server_restart_needed") + if ((lastCalled == -1)) || ((lastCalled > DOCKER_DOWN_MAIL)); then + set_last_time "server_restart_needed" + echo "Sending mail to user - manual server restart needed" + mail_restart_needed "Usługa Docker uległa awarii i nie można automatycznie jej uruchomić" + else + echo "Mail for manual restart already recently sent" + fi + fi + fi fi fi echo "Watchdog observation: $WATCHDOG_STATUS" # if [ "$WATCHDOG_LAST_STATUS" != "$WATCHDOG_STATUS" ]; then - echo "$WATCHDOG_TIME [$WATCHDOG_STATUS]" >>$WATCHDOG_LOG_FILE - LOGSIZE=$(wc -l <$WATCHDOG_LOG_FILE) + echo "$WATCHDOG_TIME [$WATCHDOG_STATUS]" >>"$WATCHDOG_LOG_FILE" + LOGSIZE=$(wc -l <"$WATCHDOG_LOG_FILE") if [ "$LOGSIZE" -gt 1000 ]; then - tail -1000 $WATCHDOG_LOG_FILE >"$WATCHDOG_LOG_FILE.tmp" + tail -1000 "$WATCHDOG_LOG_FILE" >"$WATCHDOG_LOG_FILE.tmp" mv -f "$WATCHDOG_LOG_FILE.tmp" "$WATCHDOG_LOG_FILE" fi # fi if [[ -f $WATCHDOG_FAILURES_FILE ]]; then - FAILSIZE=$(wc -l <$WATCHDOG_FAILURES_FILE) + FAILSIZE=$(wc -l <"$WATCHDOG_FAILURES_FILE") if [ "$FAILSIZE" -gt 10000 ]; then - tail -10000 $WATCHDOG_FAILURES_FILE >"$WATCHDOG_FAILURES_FILE.tmp" + tail -10000 "$WATCHDOG_FAILURES_FILE" >"$WATCHDOG_FAILURES_FILE.tmp" mv -f "$WATCHDOG_FAILURES_FILE.tmp" "$WATCHDOG_FAILURES_FILE" fi fi - echo "$WATCHDOG_TIME" >$WATCHDOG_TIME_FILE - echo "$WATCHDOG_STATUS" >$WATCHDOG_STATUS_FILE + echo "$WATCHDOG_TIME" >"$WATCHDOG_TIME_FILE" + echo "$WATCHDOG_STATUS" >"$WATCHDOG_STATUS_FILE" exit 0 } load_update_channel() { if [[ -f $UPDATE_CHANNEL_FILE ]]; then - UPDATE_CHANNEL=$(cat $UPDATE_CHANNEL_FILE) + UPDATE_CHANNEL=$(cat "$UPDATE_CHANNEL_FILE") msgok "Loaded update channel: $UPDATE_CHANNEL" fi } @@ -2379,13 +2723,13 @@ parse_commandline_args() { -d | --develop) warn "Switching to DEVELOP update channel" UPDATE_CHANNEL=develop - echo "$UPDATE_CHANNEL" >$UPDATE_CHANNEL_FILE + echo "$UPDATE_CHANNEL" >"$UPDATE_CHANNEL_FILE" shift ;; -p | --production) warn "Switching to PRODUCTION update channel" UPDATE_CHANNEL=master - echo "$UPDATE_CHANNEL" >$UPDATE_CHANNEL_FILE + echo "$UPDATE_CHANNEL" >"$UPDATE_CHANNEL_FILE" shift ;; -c | --channel) @@ -2399,7 +2743,7 @@ parse_commandline_args() { warn "Switching to $UPDATE_CHANNEL_CANDIDATE update channel" UPDATE_CHANNEL="$UPDATE_CHANNEL_CANDIDATE" - echo "$UPDATE_CHANNEL" >$UPDATE_CHANNEL_FILE + echo "$UPDATE_CHANNEL" >"$UPDATE_CHANNEL_FILE" shift ;; --) diff --git a/updated b/updated index 74577c3..b255d0b 100644 --- a/updated +++ b/updated @@ -1 +1 @@ -2024-10-12T23:27:19.837Z \ No newline at end of file +2024-10-18T08:34:23.065Z \ No newline at end of file