Compare commits
14 Commits
v1
...
c483366f4d
| Author | SHA1 | Date | |
|---|---|---|---|
| c483366f4d | |||
| 7933a21766 | |||
| 2311ff28c9 | |||
| 7feea8ccef | |||
| 7ad6b001eb | |||
| 171361480d | |||
| 08ff104659 | |||
| c3a572619f | |||
| e7ca4cb434 | |||
| c981bfd033 | |||
| d406657bfb | |||
| 2e2cf449a4 | |||
| 30a556f8f0 | |||
| 3f96d27ee9 |
1169
Cargo.lock
generated
1169
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
18
Cargo.toml
18
Cargo.toml
@@ -1,20 +1,20 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "cai-watchdog"
|
name = "cai-watchdog"
|
||||||
version = "0.9.0"
|
version = "0.5.0"
|
||||||
authors = ["Alexander I. Chebykin <alex.chebykin@gmail.com>"]
|
authors = ["Alexander I. Chebykin <alex.chebykin@gmail.com>"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
file-utils = "0.1"
|
file-utils = "0.1.5"
|
||||||
chrono = "0.4"
|
chrono = "0.4.22"
|
||||||
# Sync
|
# Sync
|
||||||
#reqwest = { version = "0.11", features = ["blocking"] }
|
#reqwest = { version = "0.11", features = ["blocking"] }
|
||||||
# Async
|
# Async
|
||||||
reqwest = "0.12"
|
reqwest = "0.11"
|
||||||
tokio = { version = "1.43", features = ["full"] }
|
tokio = { version = "1", features = ["full"] }
|
||||||
ini = "1.3"
|
ini = "1.3.0"
|
||||||
exitcode = "1.1"
|
exitcode = "1.1.2"
|
||||||
sysinfo = "0.33"
|
hashmap = "0.0.1"
|
||||||
sys-locale = "0.3"
|
sysinfo = "0.26.6"
|
||||||
|
|||||||
44
README.md
44
README.md
@@ -38,15 +38,12 @@ email = E-mail address for notifications
|
|||||||
command = Command to send notification
|
command = Command to send notification
|
||||||
```
|
```
|
||||||
|
|
||||||
In commands You can use fields ```<email>```, ```<subject>```, ```<message>```, ```<service>```, ```<uri>```, ```<process>``` and ```<state>```
|
In commands You can use fields ```<email>```, ```<subject>``` and ```<message>```
|
||||||
|
|
||||||
- ```<email>``` - E-mail address for notifications
|
- ```<email>``` - E-mail address for notifications
|
||||||
- ```<subject>``` - E-mail subject
|
- ```<subject>``` - E-mail subject
|
||||||
- ```<message>``` - Message text
|
- ```<message>``` - Message text
|
||||||
- ```<service>``` - Service name
|
|
||||||
- ```<uri>``` - Service URI (for web services)
|
|
||||||
- ```<process>``` - Process name (for OS tasks)
|
|
||||||
- ```<state>``` - Service states are ```online``` and ```offline```, process states are ```running``` and ```stopped```
|
|
||||||
### Scripts configurations
|
### Scripts configurations
|
||||||
|
|
||||||
#### *nix
|
#### *nix
|
||||||
@@ -61,18 +58,6 @@ Configuration file ```/etc/cai-watchdog/email.conf```
|
|||||||
- ```Password:``` - Set e-mail password here
|
- ```Password:``` - Set e-mail password here
|
||||||
- ```SMTP Server:``` - Set SMTP server address here
|
- ```SMTP Server:``` - Set SMTP server address here
|
||||||
- ```Port:``` - Set SMTP port here
|
- ```Port:``` - Set SMTP port here
|
||||||
|
|
||||||
##### send-mail-[locale]
|
|
||||||
|
|
||||||
**Usage:** ```send-mail-[locale] recipient 'service' 'process-or-uri' 'state'```
|
|
||||||
|
|
||||||
Configuration file ```/etc/cai-watchdog/email.conf```
|
|
||||||
|
|
||||||
- ```Username:``` - Set e-mail user name here
|
|
||||||
- ```Password:``` - Set e-mail password here
|
|
||||||
- ```SMTP Server:``` - Set SMTP server address here
|
|
||||||
- ```Port:``` - Set SMTP port here
|
|
||||||
|
|
||||||
##### send-telegram
|
##### send-telegram
|
||||||
|
|
||||||
**Usage:** ```send-telegram 'message'```
|
**Usage:** ```send-telegram 'message'```
|
||||||
@@ -81,16 +66,6 @@ Configuration file ```/etc/cai-watchdog/telegram.conf```
|
|||||||
|
|
||||||
- ```Group ID:``` - Set Telegram group ID here
|
- ```Group ID:``` - Set Telegram group ID here
|
||||||
- ```Bot token:``` - Set Telegram token here
|
- ```Bot token:``` - Set Telegram token here
|
||||||
|
|
||||||
##### send-telegram-[locale]
|
|
||||||
|
|
||||||
**Usage:** ```send-telegram-[locale] 'service', 'process-or-uri', 'state'```
|
|
||||||
|
|
||||||
Configuration file ```/etc/cai-watchdog/telegram.conf```
|
|
||||||
|
|
||||||
- ```Group ID:``` - Set Telegram group ID here
|
|
||||||
- ```Bot token:``` - Set Telegram token here
|
|
||||||
|
|
||||||
#### Windows
|
#### Windows
|
||||||
|
|
||||||
##### send-mail.ps1
|
##### send-mail.ps1
|
||||||
@@ -127,7 +102,7 @@ Next you need to find your Telegram Chat ID.
|
|||||||
|
|
||||||
### Service configuration (*nix)
|
### Service configuration (*nix)
|
||||||
|
|
||||||
If you want to get messages when watchdog service is stopped, uncomment following line: ```ExecStopPost=/etc/cai-watchdog/on-stop```
|
If you want to get messages when watchdog service is stopped, uncomment following line: ```ExecStopPost=send-telegram 'ATTENTION! Watchdog is stopped!'``` or ```#ExecStopPost=/usr/local/sbin/cai-watchdog-stopped``` if you want message with exclamation icon (⚠)
|
||||||
|
|
||||||
## User logins monitoring (*nix)
|
## User logins monitoring (*nix)
|
||||||
|
|
||||||
@@ -147,7 +122,7 @@ Watchdog can send notifications on user login. Just add to ```/etc/profile.d/ssh
|
|||||||
IP=$(echo $SSH_CONNECTION | awk '{ print $1 == "" ? "127.0.0.1" : $1 }')
|
IP=$(echo $SSH_CONNECTION | awk '{ print $1 == "" ? "127.0.0.1" : $1 }')
|
||||||
CAI_WATCHDOG_PATH=/etc/cai-watchdog
|
CAI_WATCHDOG_PATH=/etc/cai-watchdog
|
||||||
source ${CAI_WATCHDOG_PATH}/inc-icons
|
source ${CAI_WATCHDOG_PATH}/inc-icons
|
||||||
${CAI_WATCHDOG_PATH}/send-mail your@mail.addr '${ICON_INFO} SSH: User ${User} is logged in' '${ICON_INFO} SSH: User ${User} is logged in from ${IP}'
|
${CAI_WATCHDOG_PATH}//send-mail your@mail.addr '${ICON_INFO} SSH: User ${User} is logged in' '${ICON_INFO} SSH: User ${User} is logged in from ${IP}'
|
||||||
```
|
```
|
||||||
|
|
||||||
## User logouts monitoring (*nix)
|
## User logouts monitoring (*nix)
|
||||||
@@ -158,9 +133,8 @@ Watchdog can send notifications on user login. Just add to ```/etc/profile.d/ssh
|
|||||||
|
|
||||||
```
|
```
|
||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
CAI_WATCHDOG_PATH=/etc/cai-watchdog
|
|
||||||
if [ "$PAM_TYPE" = "close_session" ]; then
|
if [ "$PAM_TYPE" = "close_session" ]; then
|
||||||
${CAI_WATCHDOG_PATH}/send-telegram "SSH: User ${PAM_USER} is logged out"
|
send-telegram "SSH: User is logged out"
|
||||||
fi
|
fi
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -168,16 +142,10 @@ Watchdog can send notifications on user login. Just add to ```/etc/profile.d/ssh
|
|||||||
|
|
||||||
```
|
```
|
||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
CAI_WATCHDOG_PATH=/etc/cai-watchdog
|
|
||||||
if [ "$PAM_TYPE" = "close_session" ]; then
|
if [ "$PAM_TYPE" = "close_session" ]; then
|
||||||
${CAI_WATCHDOG_PATH}/send-mail your@mail.addr 'SSH: User ${PAM_USER} is logged out' 'SSH: User is logged out'
|
send-mail your@mail.addr 'SSH: User is logged out' 'SSH: User is logged out'
|
||||||
fi
|
fi
|
||||||
```
|
```
|
||||||
and set executable flag on it
|
and set executable flag on it
|
||||||
|
|
||||||
1. Modify ```/etc/pam.d/sshd```, add line ```session optional pam_exec.so quiet /etc/pam.d/pam_session.sh```
|
1. Modify ```/etc/pam.d/sshd```, add line ```session optional pam_exec.so quiet /etc/pam.d/pam_session.sh```
|
||||||
|
|
||||||
## Localization
|
|
||||||
You can find locales in ```/etc/cai-watchdog/locales/``` in *nix and in ```locales``` subfolder in Windows.
|
|
||||||
|
|
||||||
locale files must be named like locale_name.conf, for example: Russian locale is ru-RU.
|
|
||||||
|
|||||||
@@ -1,26 +0,0 @@
|
|||||||
[rules]
|
|
||||||
cant_find_config_file = Не могу найти файл конфигурации
|
|
||||||
check_failed = Проверка завершилась неудачей
|
|
||||||
check_is_ok = проверка завершилась успешно
|
|
||||||
configuration_file = Конфигурационный файл
|
|
||||||
error = Ошибка
|
|
||||||
execute = Выполняю
|
|
||||||
exiting = Завершаю работу...
|
|
||||||
failed_to_execute_process = Не удалось выполнить процесс
|
|
||||||
is_not_running = не запущен
|
|
||||||
is_not_running_now = сейчас не запущен
|
|
||||||
is_offline = неактивна
|
|
||||||
is_offline_now = сейчас неактивна
|
|
||||||
is_online = активна
|
|
||||||
is_online_now = сейчас активна
|
|
||||||
is_running = запущен
|
|
||||||
is_running_now = сейчас запущен
|
|
||||||
process = Процесс
|
|
||||||
service = Служба
|
|
||||||
service_started = Служба запущена
|
|
||||||
state_changed_to_false = состояние изменилось на истину
|
|
||||||
state_changed_to_true = состояние изменилось на ложь
|
|
||||||
this_help_message = Это справочное сообщение
|
|
||||||
usage = Использование
|
|
||||||
ver = версия
|
|
||||||
version_info = Информация о версии
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
APP_PATH=$(dirname "$0") # relative
|
|
||||||
APP_PATH=$(cd "$APP_PATH" && pwd) # absolutized and normalized
|
|
||||||
if [[ -z "$APP_PATH" ]] ; then
|
|
||||||
# error; for some reason, the path is not accessible
|
|
||||||
# to the script (e.g. permissions re-evaled after suid)
|
|
||||||
APP_PATH="/etc/cai-watchdog"
|
|
||||||
fi
|
|
||||||
|
|
||||||
##### DEFAULT PARAMS ORDER #####
|
|
||||||
## $1 - <email>
|
|
||||||
## $2 - <subject>
|
|
||||||
## $3 - <message>
|
|
||||||
## $4 - <service>
|
|
||||||
## $5 - <process>
|
|
||||||
## $6 - <status> [running | stopped]
|
|
||||||
|
|
||||||
EMAIL=$1
|
|
||||||
SUBJECT=$2
|
|
||||||
MESSAGE=$3
|
|
||||||
SERVICE=$4
|
|
||||||
PROCESS=$5
|
|
||||||
STATUS=$6
|
|
||||||
|
|
||||||
## SAMPLE COMMANDS
|
|
||||||
#${APP_PATH}/send-mail "${EMAIL}", "${SUBJECT}", "$MESSAGE"
|
|
||||||
#${APP_PATH}/send-telegram-ru "${SERVICE}", "${PROCESS}", "$STATUS"
|
|
||||||
|
|
||||||
${APP_PATH}/send-telegram "$MESSAGE"
|
|
||||||
@@ -1,11 +1,4 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
APP_PATH=$(dirname "$0") # relative
|
APP_PATH=/etc/cai-watchdog
|
||||||
APP_PATH=$(cd "$APP_PATH" && pwd) # absolutized and normalized
|
|
||||||
if [[ -z "$APP_PATH" ]] ; then
|
|
||||||
# error; for some reason, the path is not accessible
|
|
||||||
# to the script (e.g. permissions re-evaled after suid)
|
|
||||||
APP_PATH="/etc/cai-watchdog"
|
|
||||||
fi
|
|
||||||
|
|
||||||
source ${APP_PATH}/inc-icons
|
source ${APP_PATH}/inc-icons
|
||||||
${APP_PATH}/send-telegram "${ICON_INFO} Watchdog is started!"
|
${APP_PATH}/send-telegram "${ICON_INFO} ATTENTION! Watchdog is stopped!"
|
||||||
|
|||||||
@@ -1,11 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
APP_PATH=$(dirname "$0") # relative
|
|
||||||
APP_PATH=$(cd "$APP_PATH" && pwd) # absolutized and normalized
|
|
||||||
if [[ -z "$APP_PATH" ]] ; then
|
|
||||||
# error; for some reason, the path is not accessible
|
|
||||||
# to the script (e.g. permissions re-evaled after suid)
|
|
||||||
APP_PATH="/etc/cai-watchdog"
|
|
||||||
fi
|
|
||||||
|
|
||||||
source ${APP_PATH}/inc-icons
|
|
||||||
${APP_PATH}/send-telegram "${ICON_INFO} Watchdog запущен!"
|
|
||||||
@@ -1,11 +1,4 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
APP_PATH=$(dirname "$0") # relative
|
APP_PATH=/etc/cai-watchdog
|
||||||
APP_PATH=$(cd "$APP_PATH" && pwd) # absolutized and normalized
|
|
||||||
if [[ -z "$APP_PATH" ]] ; then
|
|
||||||
# error; for some reason, the path is not accessible
|
|
||||||
# to the script (e.g. permissions re-evaled after suid)
|
|
||||||
APP_PATH="/etc/cai-watchdog"
|
|
||||||
fi
|
|
||||||
|
|
||||||
source ${APP_PATH}/inc-icons
|
source ${APP_PATH}/inc-icons
|
||||||
${APP_PATH}/send-telegram "${ICON_WARNING} ATTENTION! Watchdog is stopped!"
|
${APP_PATH}/send-telegram "${ICON_WARNING} ATTENTION! Watchdog is stopped!"
|
||||||
|
|||||||
@@ -1,11 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
APP_PATH=$(dirname "$0") # relative
|
|
||||||
APP_PATH=$(cd "$APP_PATH" && pwd) # absolutized and normalized
|
|
||||||
if [[ -z "$APP_PATH" ]] ; then
|
|
||||||
# error; for some reason, the path is not accessible
|
|
||||||
# to the script (e.g. permissions re-evaled after suid)
|
|
||||||
APP_PATH="/etc/cai-watchdog"
|
|
||||||
fi
|
|
||||||
|
|
||||||
source ${APP_PATH}/inc-icons
|
|
||||||
${APP_PATH}/send-telegram "${ICON_WARNING} ВНИМАНИЕ! Watchdog остановлен!"
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
APP_PATH=$(dirname "$0") # relative
|
|
||||||
APP_PATH=$(cd "$APP_PATH" && pwd) # absolutized and normalized
|
|
||||||
if [[ -z "$APP_PATH" ]] ; then
|
|
||||||
# error; for some reason, the path is not accessible
|
|
||||||
# to the script (e.g. permissions re-evaled after suid)
|
|
||||||
APP_PATH="/etc/cai-watchdog"
|
|
||||||
fi
|
|
||||||
|
|
||||||
##### DEFAULT PARAMS ORDER #####
|
|
||||||
## $1 - <email>
|
|
||||||
## $2 - <subject>
|
|
||||||
## $3 - <message>
|
|
||||||
## $4 - <service>
|
|
||||||
## $5 - <uri>
|
|
||||||
## $6 - <status> [online | offline]
|
|
||||||
|
|
||||||
EMAIL=$1
|
|
||||||
SUBJECT=$2
|
|
||||||
MESSAGE=$3
|
|
||||||
SERVICE=$4
|
|
||||||
URI=$5
|
|
||||||
STATUS=$6
|
|
||||||
|
|
||||||
## SAMPLE COMMANDS
|
|
||||||
#${APP_PATH}/send-mail "${EMAIL}", "${SUBJECT}", "$MESSAGE"
|
|
||||||
#${APP_PATH}/send-telegram-ru "${SERVICE}", "${URI}", "$STATUS"
|
|
||||||
|
|
||||||
${APP_PATH}/send-telegram "$MESSAGE"
|
|
||||||
@@ -1,17 +1,9 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
APP_PATH=$(dirname "$0") # relative
|
|
||||||
APP_PATH=$(cd "$APP_PATH" && pwd) # absolutized and normalized
|
|
||||||
if [[ -z "$APP_PATH" ]] ; then
|
|
||||||
# error; for some reason, the path is not accessible
|
|
||||||
# to the script (e.g. permissions re-evaled after suid)
|
|
||||||
APP_PATH="/etc/cai-watchdog"
|
|
||||||
fi
|
|
||||||
|
|
||||||
rcpt=$1
|
rcpt=$1
|
||||||
subj=$2
|
subj=$2
|
||||||
message=$3
|
message=$3
|
||||||
|
|
||||||
ARGS=$(xargs echo $(perl -anle 's/^[^:]+//g && s/:\s+//g && print' ${APP_PATH}/email.conf) < /dev/null)
|
ARGS=$(xargs echo $(perl -anle 's/^[^:]+//g && s/:\s+//g && print' /etc/cai-watchdog/email.conf) < /dev/null)
|
||||||
set -- $ARGS "$@";
|
set -- $ARGS "$@";
|
||||||
|
|
||||||
declare -A email;
|
declare -A email;
|
||||||
|
|||||||
@@ -1,81 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
APP_PATH=$(dirname "$0") # relative
|
|
||||||
APP_PATH=$(cd "$APP_PATH" && pwd) # absolutized and normalized
|
|
||||||
if [[ -z "$APP_PATH" ]] ; then
|
|
||||||
# error; for some reason, the path is not accessible
|
|
||||||
# to the script (e.g. permissions re-evaled after suid)
|
|
||||||
APP_PATH="/etc/cai-watchdog"
|
|
||||||
fi
|
|
||||||
|
|
||||||
source ${APP_PATH}/inc-icons
|
|
||||||
|
|
||||||
RCPT=$1
|
|
||||||
SERVICE=$2
|
|
||||||
PROCESS_OR_URI=$3
|
|
||||||
STATE=$4
|
|
||||||
|
|
||||||
case $4 in
|
|
||||||
online)
|
|
||||||
SERVICE_OR_PROCESS="Служба"
|
|
||||||
STATE_STR="доступна"
|
|
||||||
ICON=${ICON_OK}
|
|
||||||
;;
|
|
||||||
running)
|
|
||||||
SERVICE_OR_PROCESS="Процесс"
|
|
||||||
STATE_STR="запущен"
|
|
||||||
ICON=${ICON_OK}
|
|
||||||
;;
|
|
||||||
offline)
|
|
||||||
SERVICE_OR_PROCESS="Служба"
|
|
||||||
STATE_STR="недоступна"
|
|
||||||
ICON=${ICON_FAIL}
|
|
||||||
;;
|
|
||||||
stopped)
|
|
||||||
SERVICE_OR_PROCESS="Процесс"
|
|
||||||
STATE_STR="остановлен"
|
|
||||||
ICON=${ICON_FAIL}
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
MESSAGE_TEXT="${ICON} ${SERVICE_OR_PROCESS} ${SERVICE} (${PROCESS_OR_URI}) ${STATE_STR}"
|
|
||||||
|
|
||||||
|
|
||||||
#subj=$2
|
|
||||||
#message=$3
|
|
||||||
|
|
||||||
ARGS=$(xargs echo $(perl -anle 's/^[^:]+//g && s/:\s+//g && print' ${APP_PATH}/email.conf) < /dev/null)
|
|
||||||
set -- $ARGS "$@";
|
|
||||||
|
|
||||||
declare -A email;
|
|
||||||
email['user']=$1
|
|
||||||
email['pass']=$2
|
|
||||||
email['smtp']=$3
|
|
||||||
email['port']=$4
|
|
||||||
|
|
||||||
email_content='From: "Watchdog" <'"${email['user']}"'>
|
|
||||||
To: "Subscriber" <'"${RCPT}"'>
|
|
||||||
Subject: '"${MESSAGE_TEXT}"'
|
|
||||||
Date: '"$(date)"'
|
|
||||||
|
|
||||||
'"${MESSAGE_TEXT}"'
|
|
||||||
-----
|
|
||||||
'"${HOSTNAME}"'
|
|
||||||
';
|
|
||||||
|
|
||||||
|
|
||||||
echo "$email_content" | curl -s \ # -vvv \
|
|
||||||
--url "smtps://${email['smtp']}:${email['port']}" \
|
|
||||||
--user "${email['user']}:${email['pass']}" \
|
|
||||||
--mail-from "${email['user']}" \
|
|
||||||
--mail-rcpt "${RCPT}" \
|
|
||||||
--upload-file - \
|
|
||||||
-T -
|
|
||||||
|
|
||||||
|
|
||||||
if [[ $? == 0 ]]; then
|
|
||||||
echo;
|
|
||||||
echo 'okay';
|
|
||||||
else
|
|
||||||
echo "curl error code $?";
|
|
||||||
man curl | grep "^ \+$? \+"
|
|
||||||
fi
|
|
||||||
@@ -1,14 +1,4 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
APP_PATH=$(dirname "$0") # relative
|
|
||||||
APP_PATH=$(cd "$APP_PATH" && pwd) # absolutized and normalized
|
|
||||||
if [[ -z "$APP_PATH" ]] ; then
|
|
||||||
# error; for some reason, the path is not accessible
|
|
||||||
# to the script (e.g. permissions re-evaled after suid)
|
|
||||||
APP_PATH="/etc/cai-watchdog"
|
|
||||||
fi
|
|
||||||
|
|
||||||
source ${APP_PATH}/inc-icons
|
|
||||||
|
|
||||||
SCRIPT_NAME=$0
|
SCRIPT_NAME=$0
|
||||||
MESSAGE_TEXT=$1
|
MESSAGE_TEXT=$1
|
||||||
|
|
||||||
@@ -17,7 +7,7 @@ if [ "$#" -ne 1 ]; then
|
|||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
ARGS=$(xargs echo $(perl -anle 's/^[^:]+//g && s/:\s+//g && print' ${APP_PATH}/telegram.conf) < /dev/null)
|
ARGS=$(xargs echo $(perl -anle 's/^[^:]+//g && s/:\s+//g && print' /etc/cai-watchdog/email.conf) < /dev/null)
|
||||||
set -- $ARGS "$@";
|
set -- $ARGS "$@";
|
||||||
|
|
||||||
GROUP_ID=$1
|
GROUP_ID=$1
|
||||||
|
|||||||
@@ -1,65 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
APP_PATH=$(dirname "$0") # relative
|
|
||||||
APP_PATH=$(cd "$APP_PATH" && pwd) # absolutized and normalized
|
|
||||||
if [[ -z "$APP_PATH" ]] ; then
|
|
||||||
# error; for some reason, the path is not accessible
|
|
||||||
# to the script (e.g. permissions re-evaled after suid)
|
|
||||||
APP_PATH="/etc/cai-watchdog"
|
|
||||||
fi
|
|
||||||
|
|
||||||
source ${APP_PATH}/inc-icons
|
|
||||||
|
|
||||||
SCRIPT_NAME=$0
|
|
||||||
SERVICE=$1
|
|
||||||
PROCESS_OR_URI=$2
|
|
||||||
STATE=$3
|
|
||||||
|
|
||||||
case $3 in
|
|
||||||
online)
|
|
||||||
SERVICE_OR_PROCESS="Служба"
|
|
||||||
STATE_STR="доступна"
|
|
||||||
ICON=${ICON_OK}
|
|
||||||
;;
|
|
||||||
running)
|
|
||||||
SERVICE_OR_PROCESS="Процесс"
|
|
||||||
STATE_STR="запущен"
|
|
||||||
ICON=${ICON_OK}
|
|
||||||
;;
|
|
||||||
offline)
|
|
||||||
SERVICE_OR_PROCESS="Служба"
|
|
||||||
STATE_STR="недоступна"
|
|
||||||
ICON=${ICON_FAIL}
|
|
||||||
;;
|
|
||||||
stopped)
|
|
||||||
SERVICE_OR_PROCESS="Процесс"
|
|
||||||
STATE_STR="остановлен"
|
|
||||||
ICON=${ICON_FAIL}
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
MESSAGE_TEXT="${ICON} ${SERVICE_OR_PROCESS} ${SERVICE} (${PROCESS_OR_URI}) ${STATE_STR}"
|
|
||||||
|
|
||||||
if [ "$#" -ne 3 ]; then
|
|
||||||
echo "Вы должны передать 3 аргумента - название службы, uri или название процесса и статус. Аргументы с пробелами требуется взять в кавычки"
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
ARGS=$(xargs echo $(perl -anle 's/^[^:]+//g && s/:\s+//g && print' ${APP_PATH}/telegram.conf) < /dev/null)
|
|
||||||
set -- $ARGS "$@";
|
|
||||||
|
|
||||||
GROUP_ID=$1
|
|
||||||
BOT_TOKEN=$2
|
|
||||||
|
|
||||||
# this 3 checks (if) are not necessary but should be convenient
|
|
||||||
if [ "${MESSAGE_TEXT}" == "-h" ]; then
|
|
||||||
echo "Usage: `basename ${SCRIPT_NAME}` \"text message\""
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ -z "${MESSAGE_TEXT}" ]
|
|
||||||
then
|
|
||||||
echo "Add message text as second arguments"
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
curl -s --data "text=${MESSAGE_TEXT}" --data "chat_id=$GROUP_ID" 'https://api.telegram.org/bot'$BOT_TOKEN'/sendMessage' > /dev/null
|
|
||||||
@@ -6,7 +6,8 @@ User=wwwrun
|
|||||||
Group=www
|
Group=www
|
||||||
Type=simple
|
Type=simple
|
||||||
ExecStart=/usr/local/sbin/cai-watchdog
|
ExecStart=/usr/local/sbin/cai-watchdog
|
||||||
ExecStopPost=/etc/cai-watchdog/on-stop
|
#ExecStopPost=/etc/cai-watchdog/on-stop
|
||||||
|
#ExecStopPost=send-telegram 'ATTENTION! Watchdog is stopped!'
|
||||||
|
|
||||||
KillMode=control-group
|
KillMode=control-group
|
||||||
NotifyAccess=all
|
NotifyAccess=all
|
||||||
|
|||||||
@@ -1,26 +0,0 @@
|
|||||||
[rules]
|
|
||||||
cant_find_config_file = Не могу найти файл конфигурации
|
|
||||||
check_failed = Проверка завершилась неудачей
|
|
||||||
check_is_ok = проверка завершилась успешно
|
|
||||||
configuration_file = Конфигурационный файл
|
|
||||||
error = Ошибка
|
|
||||||
execute = Выполняю
|
|
||||||
exiting = Завершаю работу...
|
|
||||||
failed_to_execute_process = Не удалось выполнить процесс
|
|
||||||
is_not_running = не запущен
|
|
||||||
is_not_running_now = сейчас не запущен
|
|
||||||
is_offline = неактивна
|
|
||||||
is_offline_now = сейчас неактивна
|
|
||||||
is_online = активна
|
|
||||||
is_online_now = сейчас активна
|
|
||||||
is_running = запущен
|
|
||||||
is_running_now = сейчас запущен
|
|
||||||
process = Процесс
|
|
||||||
service = Служба
|
|
||||||
service_started = Служба запущена
|
|
||||||
state_changed_to_false = состояние изменилось на истину
|
|
||||||
state_changed_to_true = состояние изменилось на ложь
|
|
||||||
this_help_message = Это справочное сообщение
|
|
||||||
usage = Использование
|
|
||||||
ver = версия
|
|
||||||
version_info = Информация о версии
|
|
||||||
287
src/main.rs
287
src/main.rs
@@ -1,22 +1,29 @@
|
|||||||
//! CAI-Watchdog is a lightweigth watchdog for *nix and Windows
|
|
||||||
//! Author: Alexander I. Chebykin (CAI) <alex.chebykin@gmail.com>
|
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate ini;
|
extern crate ini;
|
||||||
extern crate exitcode;
|
extern crate exitcode;
|
||||||
|
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
use std::process::Command;
|
||||||
use std::thread;
|
use std::thread;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
use sysinfo::{System, SystemExt};
|
||||||
|
|
||||||
mod mods;
|
/// Rule description structure
|
||||||
|
struct Rule {
|
||||||
use crate::mods::mod_debug::*;
|
/// Monitored service name
|
||||||
use crate::mods::mod_fs::*;
|
pub service: String,
|
||||||
use crate::mods::mod_i18n::*;
|
/// Monitored URI
|
||||||
use crate::mods::mod_os::*;
|
pub uri: String,
|
||||||
use crate::mods::mod_tasks::*;
|
/// Monitored process name
|
||||||
|
pub process: String,
|
||||||
|
/// E-mail address for messages
|
||||||
|
pub email: String,
|
||||||
|
/// This command will be executed on state change
|
||||||
|
pub command: String,
|
||||||
|
/// Last state
|
||||||
|
pub last_state: bool,
|
||||||
|
}
|
||||||
|
|
||||||
/// Check rule
|
/// Check rule
|
||||||
///
|
///
|
||||||
@@ -41,6 +48,34 @@ async fn check(rule: &Rule) -> bool {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Check is process running
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
///
|
||||||
|
/// * `process_name` Process name to be checked
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// if check_process("httpd".to_string()).await {
|
||||||
|
/// println!("ok");
|
||||||
|
/// } else {
|
||||||
|
/// println!("uh-oh... something wrong!");
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
fn check_process(process_name: String) -> bool {
|
||||||
|
let mut sys = System::new_all();
|
||||||
|
let mut result: bool = false;
|
||||||
|
|
||||||
|
sys.refresh_all();
|
||||||
|
|
||||||
|
for _process in sys.processes_by_exact_name(&process_name) {
|
||||||
|
result = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
/// Checks web-service availability
|
/// Checks web-service availability
|
||||||
///
|
///
|
||||||
/// # Arguments
|
/// # Arguments
|
||||||
@@ -64,6 +99,57 @@ async fn check_uri(uri: String) -> bool {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Output to console only in debug version
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
///
|
||||||
|
/// * `text` - Message text
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// debug_log("Debug version started".to_string());
|
||||||
|
/// ```
|
||||||
|
fn debug_log(text: String) {
|
||||||
|
if cfg!(debug_assertions) {
|
||||||
|
println!("{}", text);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Execute shell command
|
||||||
|
///
|
||||||
|
/// In linux sh command interpreter will be called.
|
||||||
|
/// In Windows PowerShell command interpreter will be called.
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
///
|
||||||
|
/// * `command` - Command to be executed
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// execute("gedit".to_string());
|
||||||
|
/// ```
|
||||||
|
fn execute(command: String) {
|
||||||
|
debug_log(format!("execute {}", command));
|
||||||
|
|
||||||
|
let output = if cfg!(target_os = "windows") {
|
||||||
|
Command::new("powershell")
|
||||||
|
.args(["-NoLogo", "-NonInteractive", "-Command", &command])
|
||||||
|
.output()
|
||||||
|
.expect("failed to execute process")
|
||||||
|
} else {
|
||||||
|
Command::new("sh")
|
||||||
|
.arg("-c")
|
||||||
|
.arg(&command)
|
||||||
|
.output()
|
||||||
|
.expect("failed to execute process")
|
||||||
|
};
|
||||||
|
|
||||||
|
let result = output.stdout;
|
||||||
|
debug_log(format!("{:?}", result));
|
||||||
|
}
|
||||||
|
|
||||||
/// Print help and program version information
|
/// Print help and program version information
|
||||||
///
|
///
|
||||||
/// # Arguments
|
/// # Arguments
|
||||||
@@ -78,46 +164,39 @@ async fn check_uri(uri: String) -> bool {
|
|||||||
/// print_help(args.clone());
|
/// print_help(args.clone());
|
||||||
/// ```
|
/// ```
|
||||||
fn print_help(args: Vec<String>) {
|
fn print_help(args: Vec<String>) {
|
||||||
let locale = Locale::new();
|
|
||||||
|
|
||||||
if cfg!(windows) {
|
if cfg!(windows) {
|
||||||
if args.len() > 1 && (args[1].to_string() == "/help".to_string() || args[1].to_string() == "/?".to_string()) {
|
if args.len() > 1 && (args[1].to_string() == "/help".to_string() || args[1].to_string() == "/?".to_string()) {
|
||||||
const VERSION: &str = env!("CARGO_PKG_VERSION");
|
|
||||||
|
|
||||||
println!("CAI Watchdog {} {}", locale.t().ver, VERSION);
|
|
||||||
println!("");
|
println!("");
|
||||||
println!("Usage: {} [/? | /help | /v | /ver | config_file]", &args[0]);
|
println!("Usage: {} [/? | /help | /v | /ver | config_file]", &args[0]);
|
||||||
println!(" /? | /help : {}", locale.t().this_help_message);
|
println!(" /? | /help : This help message");
|
||||||
println!(" /v | /ver : {}", locale.t().version_info);
|
println!(" /v | /ver : Version info");
|
||||||
println!(" config_file : {}", locale.t().configuration_file);
|
println!(" config_file : Configuration file");
|
||||||
|
|
||||||
std::process::exit(exitcode::OK);
|
std::process::exit(exitcode::OK);
|
||||||
} else if args.len() > 1
|
} else if args.len() > 1
|
||||||
&& (args[1].to_string() == "/ver".to_string() || args[1].to_string() == "/v".to_string()) {
|
&& (args[1].to_string() == "/ver".to_string() || args[1].to_string() == "/v".to_string()) {
|
||||||
|
|
||||||
const VERSION: &str = env!("CARGO_PKG_VERSION");
|
const VERSION: &str = env!("CARGO_PKG_VERSION");
|
||||||
|
|
||||||
println!("CAI Watchdog {} {}", locale.t().ver, VERSION);
|
println!("");
|
||||||
|
println!("CAI Watchdog ver {}", VERSION);
|
||||||
|
|
||||||
std::process::exit(exitcode::OK);
|
std::process::exit(exitcode::OK);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if args.len() > 1 && (args[1].to_string() == "--help".to_string() || args[1].to_string() == "-h".to_string()) {
|
if args.len() > 1 && (args[1].to_string() == "--help".to_string() || args[1].to_string() == "-h".to_string()) {
|
||||||
const VERSION: &str = env!("CARGO_PKG_VERSION");
|
|
||||||
|
|
||||||
println!("CAI Watchdog {} {}", locale.t().ver, VERSION);
|
|
||||||
println!("");
|
println!("");
|
||||||
println!("{}: {} [-h | --help | -v | --ver | config_file]", locale.t().usage, &args[0]);
|
println!("Usage: {} [-h | --help | -v | --ver | config_file]", &args[0]);
|
||||||
println!(" -h | --help : {}", locale.t().this_help_message);
|
println!(" -h | --help : This help message");
|
||||||
println!(" -v | --ver : {}", locale.t().version_info);
|
println!(" -v | --ver : Version info");
|
||||||
println!(" config_file : {}", locale.t().configuration_file);
|
println!(" config_file : Configuration file");
|
||||||
|
|
||||||
std::process::exit(exitcode::OK);
|
std::process::exit(exitcode::OK);
|
||||||
} else if args.len() > 1
|
} else if args.len() > 1
|
||||||
&& (args[1].to_string() == "--ver".to_string() || args[1].to_string() == "-v".to_string()) {
|
&& (args[1].to_string() == "--ver".to_string() || args[1].to_string() == "-v".to_string()) {
|
||||||
const VERSION: &str = env!("CARGO_PKG_VERSION");
|
const VERSION: &str = env!("CARGO_PKG_VERSION");
|
||||||
|
|
||||||
println!("CAI Watchdog {} {}", locale.t().ver, VERSION);
|
println!("");
|
||||||
|
println!("CAI Watchdog ver {}", VERSION);
|
||||||
|
|
||||||
std::process::exit(exitcode::OK);
|
std::process::exit(exitcode::OK);
|
||||||
}
|
}
|
||||||
@@ -125,32 +204,23 @@ fn print_help(args: Vec<String>) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let locale = Locale::new();
|
|
||||||
|
|
||||||
let args: Vec<String> = env::args().collect();
|
let args: Vec<String> = env::args().collect();
|
||||||
|
|
||||||
print_help(args.clone());
|
print_help(args.clone());
|
||||||
|
|
||||||
let mut config_file = get_exe_path();
|
let mut just_started = true;
|
||||||
|
|
||||||
if cfg!(windows) {
|
|
||||||
config_file = format!("{}\\cai-watchdog.ini", config_file);
|
|
||||||
} else {
|
|
||||||
config_file = "/etc/cai-watchdog/cai-watchdog.conf".to_string();
|
|
||||||
}
|
|
||||||
|
|
||||||
let cfg_file = if args.len() > 1 {
|
let cfg_file = if args.len() > 1 {
|
||||||
&args[1]
|
&args[1]
|
||||||
|
} else if cfg!(windows) {
|
||||||
|
"cai-watchdog.ini"
|
||||||
} else {
|
} else {
|
||||||
&config_file
|
"/etc/cai-watchdog/cai-watchdog.conf"
|
||||||
};
|
};
|
||||||
|
|
||||||
if !Path::new(cfg_file).exists() {
|
if !Path::new(cfg_file).exists() {
|
||||||
println!("\u{26a0} {}! {}.",
|
println!("\u{26a0} Error! Can't find configuration file.");
|
||||||
locale.t().error,
|
println!("Exiting...");
|
||||||
locale.t().cant_find_config_file
|
|
||||||
);
|
|
||||||
println!("{}", locale.t().exiting);
|
|
||||||
|
|
||||||
std::process::exit(exitcode::CONFIG);
|
std::process::exit(exitcode::CONFIG);
|
||||||
}
|
}
|
||||||
@@ -169,36 +239,35 @@ fn main() {
|
|||||||
0
|
0
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut tasks_prc = vec![];
|
let mut tasks = vec![];
|
||||||
let mut tasks_web = vec![];
|
|
||||||
|
|
||||||
for i in 1..rules_count + 1 {
|
for i in 1..rules_count + 1 {
|
||||||
let service = if cfg[&format!("rule{}", i)].contains_key("service") {
|
let service = if cfg[&format!("{}{}", "rule", i)].contains_key("service") {
|
||||||
cfg[&format!("rule{}", i)]["service"].clone().unwrap()
|
cfg[&format!("{}{}", "rule", i)]["service"].clone().unwrap()
|
||||||
} else {
|
} else {
|
||||||
format!("Service {}", i)
|
format!("Service {}", i)
|
||||||
};
|
};
|
||||||
|
|
||||||
let uri = if cfg[&format!("rule{}", i)].contains_key("uri") {
|
let uri = if cfg[&format!("{}{}", "rule", i)].contains_key("uri") {
|
||||||
cfg[&format!("rule{}", i)]["uri"].clone().unwrap()
|
cfg[&format!("{}{}", "rule", i)]["uri"].clone().unwrap()
|
||||||
} else {
|
} else {
|
||||||
"".to_string()
|
"".to_string()
|
||||||
};
|
};
|
||||||
|
|
||||||
let process = if cfg[&format!("rule{}", i)].contains_key("process") {
|
let process = if cfg[&format!("{}{}", "rule", i)].contains_key("process") {
|
||||||
cfg[&format!("rule{}", i)]["process"].clone().unwrap()
|
cfg[&format!("{}{}", "rule", i)]["process"].clone().unwrap()
|
||||||
} else {
|
} else {
|
||||||
"".to_string()
|
"".to_string()
|
||||||
};
|
};
|
||||||
|
|
||||||
let email = if cfg[&format!("rule{}", i)].contains_key("email") {
|
let email = if cfg[&format!("{}{}", "rule", i)].contains_key("email") {
|
||||||
cfg[&format!("rule{}", i)]["email"].clone().unwrap()
|
cfg[&format!("{}{}", "rule", i)]["email"].clone().unwrap()
|
||||||
} else {
|
} else {
|
||||||
"".to_string()
|
"".to_string()
|
||||||
};
|
};
|
||||||
|
|
||||||
let command = if cfg[&format!("rule{}", i)].contains_key("command") {
|
let command = if cfg[&format!("{}{}", "rule", i)].contains_key("command") {
|
||||||
cfg[&format!("rule{}", i)]["command"].clone().unwrap()
|
cfg[&format!("{}{}", "rule", i)]["command"].clone().unwrap()
|
||||||
} else {
|
} else {
|
||||||
"".to_string()
|
"".to_string()
|
||||||
};
|
};
|
||||||
@@ -210,8 +279,7 @@ fn main() {
|
|||||||
debug_log(format!("email {}", email));
|
debug_log(format!("email {}", email));
|
||||||
debug_log(format!("command {}", command));
|
debug_log(format!("command {}", command));
|
||||||
|
|
||||||
if uri != "".to_string() {
|
tasks.push(
|
||||||
tasks_web.push(
|
|
||||||
Rule{
|
Rule{
|
||||||
service: service,
|
service: service,
|
||||||
uri: uri,
|
uri: uri,
|
||||||
@@ -221,18 +289,6 @@ fn main() {
|
|||||||
last_state: false,
|
last_state: false,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
} else {
|
|
||||||
tasks_prc.push(
|
|
||||||
Rule{
|
|
||||||
service: service,
|
|
||||||
uri: uri,
|
|
||||||
process: process,
|
|
||||||
email: email,
|
|
||||||
command: command,
|
|
||||||
last_state: false,
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let on_start_command = if cfg["main"].contains_key("on_start_command") {
|
let on_start_command = if cfg["main"].contains_key("on_start_command") {
|
||||||
@@ -241,50 +297,87 @@ fn main() {
|
|||||||
"".to_string()
|
"".to_string()
|
||||||
};
|
};
|
||||||
|
|
||||||
debug_log(format!("\u{2139} {}", locale.t().service_started));
|
debug_log("\u{2139} Service started".to_string());
|
||||||
|
|
||||||
if on_start_command.to_string() != "" {
|
if on_start_command.to_string() != "" {
|
||||||
execute(on_start_command);
|
execute(on_start_command);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut just_started_web = true;
|
|
||||||
|
|
||||||
std::thread::spawn(move || {
|
|
||||||
loop {
|
loop {
|
||||||
for i in 0..tasks_web.len() {
|
for i in 0..tasks.len() {
|
||||||
let rt = tokio::runtime::Runtime::new().unwrap();
|
let rt = tokio::runtime::Runtime::new().unwrap();
|
||||||
|
|
||||||
rt.block_on(async {
|
rt.block_on(async {
|
||||||
if check(&tasks_web[i]).await {
|
//if check(tasks[i].uri.clone()).await {
|
||||||
execute_web_task(&mut tasks_web[i], true, just_started_web);
|
if check(&tasks[i]).await {
|
||||||
|
if tasks[i].last_state != true || just_started {
|
||||||
|
if tasks[i].command.to_string() == "".to_string() {
|
||||||
|
println!("\u{2705} {} state changed to true", tasks[i].uri);
|
||||||
} else {
|
} else {
|
||||||
execute_web_task(&mut tasks_web[i], false, just_started_web);
|
debug_log(format!("\u{2705} {} state changed to true", tasks[i].uri));
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
just_started_web = false;
|
let shell_cmd = if tasks[i].uri.to_string() != "".to_string() {
|
||||||
|
tasks[i].command.to_string()
|
||||||
thread::sleep(Duration::from_millis(check_interval));
|
.replace("<email>", &tasks[i].email)
|
||||||
}
|
.replace("<subject>", &format!("\"\u{2705} Service {} ({}) is online\"", tasks[i].service, tasks[i].uri))
|
||||||
});
|
.replace("<message>", &format!("\"\u{2705} Service {} ({}) is online now\"", tasks[i].service, tasks[i].uri))
|
||||||
|
|
||||||
let mut just_started_prc = true;
|
|
||||||
|
|
||||||
loop {
|
|
||||||
for i in 0..tasks_prc.len() {
|
|
||||||
let rt = tokio::runtime::Runtime::new().unwrap();
|
|
||||||
|
|
||||||
rt.block_on(async {
|
|
||||||
if check(&tasks_prc[i]).await {
|
|
||||||
execute_os_task(&mut tasks_prc[i], true, just_started_prc);
|
|
||||||
} else {
|
} else {
|
||||||
execute_os_task(&mut tasks_prc[i], false, just_started_prc);
|
tasks[i].command.to_string()
|
||||||
|
.replace("<email>", &tasks[i].email)
|
||||||
|
.replace("<subject>", &format!("\"\u{2705} Process {} ({}) is running\"", tasks[i].service, tasks[i].process))
|
||||||
|
.replace("<message>", &format!("\"\u{2705} Process {} ({}) is running now\"", tasks[i].service, tasks[i].process))
|
||||||
|
};
|
||||||
|
|
||||||
|
debug_log(format!("execute {}", shell_cmd));
|
||||||
|
|
||||||
|
execute(shell_cmd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if tasks[i].uri.to_string() != "".to_string() {
|
||||||
|
debug_log(format!("\u{2705} {} check is ok", tasks[i].uri));
|
||||||
|
} else {
|
||||||
|
debug_log(format!("\u{2705} {} is running", tasks[i].process));
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks[i].last_state = true;
|
||||||
|
} else {
|
||||||
|
if tasks[i].last_state != false || just_started {
|
||||||
|
if tasks[i].command.to_string() == "".to_string() {
|
||||||
|
println!("\u{274c} {} state changed to false", tasks[i].uri);
|
||||||
|
} else {
|
||||||
|
debug_log(format!("\u{274c} {} state changed to false", tasks[i].uri));
|
||||||
|
|
||||||
|
let shell_cmd = if tasks[i].uri.to_string() != "".to_string() {
|
||||||
|
tasks[i].command.to_string()
|
||||||
|
.replace("<email>", &tasks[i].email)
|
||||||
|
.replace("<subject>", &format!("\"\u{274c} Service {} ({}) is offline\"", tasks[i].service, tasks[i].uri))
|
||||||
|
.replace("<message>", &format!("\"\u{274c} Service {} ({}) is offline now\"", tasks[i].service, tasks[i].uri))
|
||||||
|
} else {
|
||||||
|
tasks[i].command.to_string()
|
||||||
|
.replace("<email>", &tasks[i].email)
|
||||||
|
.replace("<subject>", &format!("\"\u{274c} Process {} ({}) is not running\"", tasks[i].service, tasks[i].process))
|
||||||
|
.replace("<message>", &format!("\"\u{274c} Process {} ({}) is not running now\"", tasks[i].service, tasks[i].process))
|
||||||
|
};
|
||||||
|
|
||||||
|
debug_log(format!("execute {}", shell_cmd));
|
||||||
|
execute(shell_cmd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if tasks[i].uri.to_string() != "".to_string() {
|
||||||
|
debug_log(format!("\u{274c} {} check failed", tasks[i].uri));
|
||||||
|
} else {
|
||||||
|
debug_log(format!("\u{274c} {} is not running", tasks[i].process));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
tasks[i].last_state = false;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
just_started_prc = false;
|
just_started = false;
|
||||||
|
|
||||||
thread::sleep(Duration::from_millis(check_interval));
|
thread::sleep(Duration::from_millis(check_interval));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +0,0 @@
|
|||||||
pub mod mod_debug;
|
|
||||||
pub mod mod_fs;
|
|
||||||
pub mod mod_i18n;
|
|
||||||
pub mod mod_os;
|
|
||||||
pub mod mod_tasks;
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
/// Output to console only in debug version
|
|
||||||
///
|
|
||||||
/// # Arguments
|
|
||||||
///
|
|
||||||
/// * `text` - Message text
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// debug_log("Debug version started".to_string());
|
|
||||||
/// ```
|
|
||||||
pub fn debug_log(text: String) {
|
|
||||||
if cfg!(debug_assertions) {
|
|
||||||
println!("{}", text);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
//! CAI-Watchdog filesystem module
|
|
||||||
//! Author: Alexander I. Chebykin (CAI) <alex.chebykin@gmail.com>
|
|
||||||
|
|
||||||
use std::env;
|
|
||||||
use std::path::PathBuf;
|
|
||||||
|
|
||||||
/// Return executable path
|
|
||||||
///
|
|
||||||
/// Return executable path or . if can't determine it
|
|
||||||
pub fn get_exe_path() -> String {
|
|
||||||
let mut dir;
|
|
||||||
let exe_path: String;
|
|
||||||
|
|
||||||
match env::current_exe() {
|
|
||||||
Ok(full_name) => {
|
|
||||||
dir = PathBuf::from(full_name);
|
|
||||||
dir.pop();
|
|
||||||
exe_path = dir.clone().into_os_string().into_string().unwrap();
|
|
||||||
},
|
|
||||||
Err(_e) => {
|
|
||||||
exe_path = ".".to_string();
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
return exe_path;
|
|
||||||
}
|
|
||||||
@@ -1,185 +0,0 @@
|
|||||||
//! CAI-Watchdog localization module
|
|
||||||
//! Author: Alexander I. Chebykin (CAI) <alex.chebykin@gmail.com>
|
|
||||||
//!
|
|
||||||
//! External localizations stored in /locales/ directory
|
|
||||||
|
|
||||||
use std::borrow::Borrow;
|
|
||||||
use std::path::Path;
|
|
||||||
|
|
||||||
use crate::mods::mod_fs;
|
|
||||||
use sys_locale::get_locale;
|
|
||||||
|
|
||||||
pub struct Lang {
|
|
||||||
pub cant_find_config_file: String,
|
|
||||||
pub check_failed: String,
|
|
||||||
pub check_is_ok: String,
|
|
||||||
pub configuration_file: String,
|
|
||||||
pub error: String,
|
|
||||||
pub execute: String,
|
|
||||||
pub exiting: String,
|
|
||||||
pub failed_to_execute_process: String,
|
|
||||||
pub is_not_running: String,
|
|
||||||
pub is_not_running_now: String,
|
|
||||||
pub is_offline: String,
|
|
||||||
pub is_offline_now: String,
|
|
||||||
pub is_online: String,
|
|
||||||
pub is_online_now: String,
|
|
||||||
pub is_running: String,
|
|
||||||
pub is_running_now: String,
|
|
||||||
pub process: String,
|
|
||||||
pub service: String,
|
|
||||||
pub service_started: String,
|
|
||||||
pub state_changed_to_false: String,
|
|
||||||
pub state_changed_to_true: String,
|
|
||||||
pub this_help_message: String,
|
|
||||||
pub usage: String,
|
|
||||||
pub ver: String,
|
|
||||||
pub version_info: String
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Locale {
|
|
||||||
pub locale:Lang,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Locale {
|
|
||||||
pub fn new() -> Self {
|
|
||||||
let mut l:Lang = Lang{
|
|
||||||
cant_find_config_file: "Can't find configuration file".to_string(),
|
|
||||||
check_failed: "check failed".to_string(),
|
|
||||||
check_is_ok: "check is ok".to_string(),
|
|
||||||
configuration_file: "Configuration file".to_string(),
|
|
||||||
error: "Error".to_string(),
|
|
||||||
execute: "Execute".to_string(),
|
|
||||||
exiting: "Exiting...".to_string(),
|
|
||||||
failed_to_execute_process: "Can't execute process".to_string(),
|
|
||||||
is_not_running: "is not running".to_string(),
|
|
||||||
is_not_running_now: "is not running now".to_string(),
|
|
||||||
is_offline: "is offline".to_string(),
|
|
||||||
is_offline_now: "is offline now".to_string(),
|
|
||||||
is_online: "is online".to_string(),
|
|
||||||
is_online_now: "is online now".to_string(),
|
|
||||||
is_running: "is running".to_string(),
|
|
||||||
is_running_now: "is running now".to_string(),
|
|
||||||
process: "Process".to_string(),
|
|
||||||
service: "Service".to_string(),
|
|
||||||
service_started: "Service started".to_string(),
|
|
||||||
state_changed_to_false: "state changed to false".to_string(),
|
|
||||||
state_changed_to_true: "state changed to true".to_string(),
|
|
||||||
this_help_message: "This help message".to_string(),
|
|
||||||
usage: "Usage".to_string(),
|
|
||||||
ver: "ver".to_string(),
|
|
||||||
version_info: "Version info".to_string()
|
|
||||||
};
|
|
||||||
|
|
||||||
let locale = get_locale().unwrap_or_else(|| String::from("en-US"));
|
|
||||||
|
|
||||||
let mut locale_file = mod_fs::get_exe_path();
|
|
||||||
|
|
||||||
locale_file = if cfg!(windows) {
|
|
||||||
format!("{}\\locales\\{}.conf", locale_file, locale)
|
|
||||||
} else {
|
|
||||||
format!("/etc/cai-watchdog/locales/{}.conf", locale)
|
|
||||||
};
|
|
||||||
|
|
||||||
if Path::new(&locale_file).exists() {
|
|
||||||
let cfg = ini!(&locale_file);
|
|
||||||
|
|
||||||
if cfg["rules"].contains_key("cant_find_config_file") {
|
|
||||||
l.cant_find_config_file = cfg["rules"]["cant_find_config_file"].clone().unwrap();
|
|
||||||
}
|
|
||||||
if cfg["rules"].contains_key("check_failed") {
|
|
||||||
l.check_failed = cfg["rules"]["check_failed"].clone().unwrap();
|
|
||||||
}
|
|
||||||
if cfg["rules"].contains_key("check_is_ok") {
|
|
||||||
l.check_is_ok = cfg["rules"]["check_is_ok"].clone().unwrap();
|
|
||||||
}
|
|
||||||
if cfg["rules"].contains_key("configuration_file") {
|
|
||||||
l.configuration_file = cfg["rules"]["configuration_file"].clone().unwrap();
|
|
||||||
}
|
|
||||||
if cfg["rules"].contains_key("error") {
|
|
||||||
l.error = cfg["rules"]["error"].clone().unwrap();
|
|
||||||
}
|
|
||||||
if cfg["rules"].contains_key("execute") {
|
|
||||||
l.execute = cfg["rules"]["execute"].clone().unwrap();
|
|
||||||
}
|
|
||||||
if cfg["rules"].contains_key("exiting") {
|
|
||||||
l.exiting = cfg["rules"]["exiting"].clone().unwrap();
|
|
||||||
}
|
|
||||||
if cfg["rules"].contains_key("failed_to_execute_process") {
|
|
||||||
l.failed_to_execute_process = cfg["rules"]["failed_to_execute_process"].clone().unwrap();
|
|
||||||
}
|
|
||||||
if cfg["rules"].contains_key("is_not_running") {
|
|
||||||
l.is_not_running = cfg["rules"]["is_not_running"].clone().unwrap();
|
|
||||||
}
|
|
||||||
if cfg["rules"].contains_key("is_not_running_now") {
|
|
||||||
l.is_not_running_now = cfg["rules"]["is_not_running_now"].clone().unwrap();
|
|
||||||
}
|
|
||||||
if cfg["rules"].contains_key("is_offline") {
|
|
||||||
l.is_offline = cfg["rules"]["is_offline"].clone().unwrap();
|
|
||||||
}
|
|
||||||
if cfg["rules"].contains_key("is_offline_now") {
|
|
||||||
l.is_offline_now = cfg["rules"]["is_offline_now"].clone().unwrap();
|
|
||||||
}
|
|
||||||
if cfg["rules"].contains_key("is_online") {
|
|
||||||
l.is_online = cfg["rules"]["is_online"].clone().unwrap();
|
|
||||||
}
|
|
||||||
if cfg["rules"].contains_key("is_online_now") {
|
|
||||||
l.is_online_now = cfg["rules"]["is_online_now"].clone().unwrap();
|
|
||||||
}
|
|
||||||
if cfg["rules"].contains_key("is_running") {
|
|
||||||
l.is_running = cfg["rules"]["is_running"].clone().unwrap();
|
|
||||||
}
|
|
||||||
if cfg["rules"].contains_key("is_running_now") {
|
|
||||||
l.is_running_now = cfg["rules"]["is_running_now"].clone().unwrap();
|
|
||||||
}
|
|
||||||
if cfg["rules"].contains_key("process") {
|
|
||||||
l.process = cfg["rules"]["process"].clone().unwrap();
|
|
||||||
}
|
|
||||||
if cfg["rules"].contains_key("service") {
|
|
||||||
l.service = cfg["rules"]["service"].clone().unwrap();
|
|
||||||
}
|
|
||||||
if cfg["rules"].contains_key("service_started") {
|
|
||||||
l.service_started = cfg["rules"]["service_started"].clone().unwrap();
|
|
||||||
}
|
|
||||||
if cfg["rules"].contains_key("state_changed_to_false") {
|
|
||||||
l.state_changed_to_false = cfg["rules"]["state_changed_to_false"].clone().unwrap();
|
|
||||||
}
|
|
||||||
if cfg["rules"].contains_key("state_changed_to_true") {
|
|
||||||
l.state_changed_to_true = cfg["rules"]["state_changed_to_true"].clone().unwrap();
|
|
||||||
}
|
|
||||||
if cfg["rules"].contains_key("this_help_message") {
|
|
||||||
l.this_help_message = cfg["rules"]["this_help_message"].clone().unwrap();
|
|
||||||
}
|
|
||||||
if cfg["rules"].contains_key("usage") {
|
|
||||||
l.usage = cfg["rules"]["usage"].clone().unwrap();
|
|
||||||
}
|
|
||||||
if cfg["rules"].contains_key("ver") {
|
|
||||||
l.ver = cfg["rules"]["ver"].clone().unwrap();
|
|
||||||
}
|
|
||||||
if cfg["rules"].contains_key("version_info") {
|
|
||||||
l.version_info = cfg["rules"]["version_info"].clone().unwrap();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Self {
|
|
||||||
locale: l
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Return object with locale data
|
|
||||||
///
|
|
||||||
/// If there is no localization file for current system locale, fallback (English) locale will be returned
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// let locale = mod_locales::Locale::new();
|
|
||||||
///
|
|
||||||
/// println!("\u{26a0} {}! {}.", locale.t().error, locale.t().cant_find_config_file);
|
|
||||||
/// println!("{}", locale.t().exiting);
|
|
||||||
/// ```
|
|
||||||
pub fn t(&self) -> &Lang {
|
|
||||||
return self.locale.borrow();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,70 +0,0 @@
|
|||||||
use std::ffi::OsStr;
|
|
||||||
use std::process::Command;
|
|
||||||
use sysinfo::System;
|
|
||||||
|
|
||||||
use crate::mods::mod_debug::*;
|
|
||||||
use crate::mods::mod_i18n::*;
|
|
||||||
|
|
||||||
/// Check is process running
|
|
||||||
///
|
|
||||||
/// # Arguments
|
|
||||||
///
|
|
||||||
/// * `process_name` Process name to be checked
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// if check_process("httpd".to_string()).await {
|
|
||||||
/// println!("ok");
|
|
||||||
/// } else {
|
|
||||||
/// println!("uh-oh... something wrong!");
|
|
||||||
/// }
|
|
||||||
/// ```
|
|
||||||
pub fn check_process(process_name: String) -> bool {
|
|
||||||
let mut sys = System::new_all();
|
|
||||||
let mut result: bool = false;
|
|
||||||
|
|
||||||
sys.refresh_all();
|
|
||||||
|
|
||||||
for _process in sys.processes_by_exact_name(OsStr::new(&process_name)) {
|
|
||||||
result = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Execute shell command
|
|
||||||
///
|
|
||||||
/// In linux sh command interpreter will be called.
|
|
||||||
/// In Windows PowerShell command interpreter will be called.
|
|
||||||
///
|
|
||||||
/// # Arguments
|
|
||||||
///
|
|
||||||
/// * `command` - Command to be executed
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// execute("gedit".to_string());
|
|
||||||
/// ```
|
|
||||||
pub fn execute(command: String) {
|
|
||||||
let locale = Locale::new();
|
|
||||||
|
|
||||||
debug_log(format!("{} {}", locale.t().execute, command));
|
|
||||||
|
|
||||||
let output = if cfg!(target_os = "windows") {
|
|
||||||
Command::new("powershell")
|
|
||||||
.args(["-NoLogo", "-NonInteractive", "-Command", &command])
|
|
||||||
.output()
|
|
||||||
.expect(&locale.t().failed_to_execute_process) //.expect("failed to execute process")
|
|
||||||
} else {
|
|
||||||
Command::new("sh")
|
|
||||||
.arg("-c")
|
|
||||||
.arg(&command)
|
|
||||||
.output()
|
|
||||||
.expect(&locale.t().failed_to_execute_process) //.expect("failed to execute process")
|
|
||||||
};
|
|
||||||
|
|
||||||
let result = output.stdout;
|
|
||||||
debug_log(format!("{:?}", result));
|
|
||||||
}
|
|
||||||
@@ -1,206 +0,0 @@
|
|||||||
use crate::mods::mod_debug::*;
|
|
||||||
use crate::mods::mod_i18n::*;
|
|
||||||
use crate::mods::mod_os::*;
|
|
||||||
|
|
||||||
pub struct Rule {
|
|
||||||
/// Monitored service name
|
|
||||||
pub service: String,
|
|
||||||
/// Monitored URI
|
|
||||||
pub uri: String,
|
|
||||||
/// Monitored process name
|
|
||||||
pub process: String,
|
|
||||||
/// E-mail address for messages
|
|
||||||
pub email: String,
|
|
||||||
/// This command will be executed on state change
|
|
||||||
pub command: String,
|
|
||||||
/// Last state
|
|
||||||
pub last_state: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn execute_web_task(task: &mut Rule, current_state:bool, just_started: bool) {
|
|
||||||
let locale = Locale::new();
|
|
||||||
|
|
||||||
if task.last_state != current_state || just_started {
|
|
||||||
if task.command.to_string() == "".to_string() {
|
|
||||||
if current_state {
|
|
||||||
println!("\u{2705} {} {}", task.uri, locale.t().state_changed_to_true.clone());
|
|
||||||
} else {
|
|
||||||
println!("\u{274c} {} {}", task.uri, locale.t().state_changed_to_false.clone());
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if current_state {
|
|
||||||
debug_log(
|
|
||||||
format!(
|
|
||||||
"\u{2705} {} {}",
|
|
||||||
task.uri,
|
|
||||||
locale.t().state_changed_to_true.clone()
|
|
||||||
)
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
debug_log(
|
|
||||||
format!(
|
|
||||||
"\u{274c} {} {}",
|
|
||||||
task.uri,
|
|
||||||
locale.t().state_changed_to_false.clone()
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
let subject: String = if current_state {
|
|
||||||
format!(
|
|
||||||
"\"\u{2705} {} {} ({}) {}\"",
|
|
||||||
locale.t().service,
|
|
||||||
task.service,
|
|
||||||
task.uri,
|
|
||||||
locale.t().is_online.clone()
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
format!(
|
|
||||||
"\"\u{274c} {} {} ({}) {}\"",
|
|
||||||
locale.t().service,
|
|
||||||
task.service,
|
|
||||||
task.uri,
|
|
||||||
locale.t().is_offline.clone()
|
|
||||||
)
|
|
||||||
};
|
|
||||||
|
|
||||||
let shell_cmd =
|
|
||||||
task.command.to_string()
|
|
||||||
.replace("<email>", &task.email)
|
|
||||||
.replace("<subject>", &subject)
|
|
||||||
.replace("<message>", &subject)
|
|
||||||
.replace("<service>", &task.service)
|
|
||||||
.replace("<uri>", &task.uri)
|
|
||||||
.replace(
|
|
||||||
"<state>",
|
|
||||||
if current_state {
|
|
||||||
"online"
|
|
||||||
} else {
|
|
||||||
"offline"
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
debug_log(format!("{} {}", locale.t().execute, shell_cmd));
|
|
||||||
|
|
||||||
execute(shell_cmd);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if current_state {
|
|
||||||
debug_log(
|
|
||||||
format!(
|
|
||||||
"\u{2705} {} {}",
|
|
||||||
task.uri,
|
|
||||||
locale.t().check_is_ok.clone()
|
|
||||||
)
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
debug_log(
|
|
||||||
format!(
|
|
||||||
"\u{274c} {} {}",
|
|
||||||
task.uri,
|
|
||||||
locale.t().check_failed.clone()
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
task.last_state = current_state;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn execute_os_task(task: &mut Rule, current_state:bool, just_started: bool) {
|
|
||||||
let locale = Locale::new();
|
|
||||||
|
|
||||||
if task.last_state != current_state || just_started {
|
|
||||||
if task.command.to_string() == "".to_string() {
|
|
||||||
if current_state {
|
|
||||||
println!(
|
|
||||||
"\u{2705} {} {}",
|
|
||||||
task.uri,
|
|
||||||
locale.t().state_changed_to_true.clone()
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
println!(
|
|
||||||
"\u{274c} {} {}",
|
|
||||||
task.uri,
|
|
||||||
locale.t().state_changed_to_false.clone()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if current_state {
|
|
||||||
debug_log(
|
|
||||||
format!(
|
|
||||||
"\u{2705} {} {}",
|
|
||||||
task.uri,
|
|
||||||
locale.t().state_changed_to_true.clone()
|
|
||||||
)
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
debug_log(
|
|
||||||
format!(
|
|
||||||
"\u{274c} {} {}",
|
|
||||||
task.uri,
|
|
||||||
locale.t().state_changed_to_false.clone()
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
let subject: String = if current_state {
|
|
||||||
format!(
|
|
||||||
"\"\u{2705} {} {} ({}) {}\"",
|
|
||||||
locale.t().process,
|
|
||||||
task.service,
|
|
||||||
task.process,
|
|
||||||
locale.t().is_running.clone()
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
format!(
|
|
||||||
"\"\u{274c} {} {} ({}) {}\"",
|
|
||||||
locale.t().process,
|
|
||||||
task.service,
|
|
||||||
task.process,
|
|
||||||
locale.t().is_not_running.clone()
|
|
||||||
)
|
|
||||||
};
|
|
||||||
|
|
||||||
let shell_cmd =
|
|
||||||
task.command.to_string()
|
|
||||||
.replace("<email>", &task.email)
|
|
||||||
.replace("<subject>", &subject)
|
|
||||||
.replace("<message>", &subject)
|
|
||||||
.replace("<service>", &task.service)
|
|
||||||
.replace("<process>", &task.process)
|
|
||||||
.replace(
|
|
||||||
"<state>",
|
|
||||||
if current_state {
|
|
||||||
"running"
|
|
||||||
} else {
|
|
||||||
"stopped"
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
debug_log(format!("{} {}", locale.t().execute, shell_cmd));
|
|
||||||
|
|
||||||
execute(shell_cmd);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if current_state {
|
|
||||||
debug_log(
|
|
||||||
format!(
|
|
||||||
"\u{2705} {} {}",
|
|
||||||
task.process,
|
|
||||||
locale.t().is_running
|
|
||||||
)
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
debug_log(
|
|
||||||
format!(
|
|
||||||
"\u{274c} {} {}",
|
|
||||||
task.process,
|
|
||||||
locale.t().is_not_running
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
task.last_state = current_state;
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user