Compare commits

..

59 Commits

Author SHA1 Message Date
878386bdd3 Merge pull request 'v1' (#23) from v1 into master
Reviewed-on: #23
2025-04-11 10:29:37 +03:00
611850435d dependencies upgrade
Dependencies upgraded to latest versions
2025-01-29 01:07:45 +03:00
8244282fa4 code refactoring
code refactoring
2025-01-28 01:33:22 +03:00
b67f987031 code refactoring
code refactoring
2025-01-28 01:23:23 +03:00
74cbb0bb5f libs updated
libs updated
2025-01-27 21:27:46 +03:00
b4672e4057 tiny refactoring
tiny refactoring
2023-11-20 01:53:23 +03:00
b91b30b1e0 dependencies updated
dependencies updated
2023-11-20 01:14:16 +03:00
b01a9f3828 dependencies updated
dependencies updated
2023-11-20 00:56:45 +03:00
a6737308c2 Merge pull request 'fixed typo in file name' (#22) from v1 into master
Reviewed-on: https://www.cainet.info/git/cai/CAI-Watchdog/pulls/22
2022-12-26 02:16:54 +03:00
a99c60d529 fixed typo in file name
fixed typo in file name
2022-12-15 20:58:09 +03:00
bd9e0b01f6 Merge pull request 'v1' (#21) from v1 into master
Reviewed-on: https://www.cainet.info/git/cai/CAI-Watchdog/pulls/21
2022-11-12 19:45:58 +03:00
82f1c744dc Tiny doc update
Tiny doc update
2022-11-12 19:40:13 +03:00
011e79e676 Locales are in external files now
Locales are in external files now
2022-11-12 19:08:33 +03:00
3ea4c96cfc Localization support added
Localization support added
2022-11-06 22:04:45 +03:00
c8d080d7b0 Merge pull request 'v1' (#20) from v1 into master
Reviewed-on: https://www.cainet.info/git/cai/CAI-Watchdog/pulls/20
2022-11-04 01:09:47 +03:00
bf96109742 Web-checks now runs in separate thread. Some fixes in scripts.
Web-checks now runs in separate thread. Some fixes in scripts.
2022-11-04 01:07:07 +03:00
87e326e869 Minor changes
Minor changes
2022-10-30 23:38:19 +03:00
dbb860a00b Merge pull request 'Update README.md' (#19) from v1 into master
Reviewed-on: https://www.cainet.info/git/cai/CAI-Watchdog/pulls/19
2022-10-30 23:02:49 +03:00
c78bb31b69 Update README.md 2022-10-30 22:59:39 +03:00
fa6c131e9b Merge pull request 'on-start script updated, localized scripts added' (#18) from v1 into master
Reviewed-on: https://www.cainet.info/git/cai/CAI-Watchdog/pulls/18
2022-10-29 21:15:37 +03:00
85654f51a0 on-start script updated, localized scripts added
on-start script updated, localized scripts added
2022-10-29 21:15:02 +03:00
2e8a323210 Merge pull request 'tiny bug fixed' (#17) from v1 into master
Reviewed-on: https://www.cainet.info/git/cai/CAI-Watchdog/pulls/17
2022-10-29 21:07:08 +03:00
fafcdfa9c7 tiny bug fixed
tiny bug fixed
2022-10-29 21:06:28 +03:00
7e6b3afcdc Merge pull request 'Localized sending scripts added' (#16) from v1 into master
Reviewed-on: https://www.cainet.info/git/cai/CAI-Watchdog/pulls/16
2022-10-29 20:55:32 +03:00
4036a703c8 Localized sending scripts added
Localized sending scripts added
2022-10-29 20:54:23 +03:00
7e91e04afb Merge pull request 'Three more report fields added - <service>, <uri> and <process>' (#15) from v1 into master
Reviewed-on: https://www.cainet.info/git/cai/CAI-Watchdog/pulls/15
2022-10-29 19:11:54 +03:00
56adae89ec Three more report fields added - <service>, <uri> and <process>
Three more report fields added - <service>, <uri> and <process>
2022-10-29 19:11:07 +03:00
c483366f4d Merge pull request 'v1' (#14) from v1 into master
Reviewed-on: https://www.cainet.info/git/cai/CAI-Watchdog/pulls/14
2022-10-29 16:59:57 +03:00
f1d16093b6 Now you can run script on watchdog startup. File structure changed on *nix. Some changes in config file and scripts, please check on upgrade.
Now you can run script on watchdog startup. File structure changed on *nix. Some changes in config file and scripts, please check on upgrade.
2022-10-29 16:57:57 +03:00
Alexander I. Chebykin
fa19c8327b Minor changes 2022-08-10 10:08:27 +03:00
fa0ec74b35 Merge branch 'v1' of https://www.cainet.info/git/cai/CAI-Watchdog into v1 2022-07-03 23:44:32 +03:00
7b98b16e6e Update main.rs 2022-07-03 23:44:07 +03:00
7933a21766 Merge pull request 'Update README.md' (#13) from v1 into master
Reviewed-on: https://www.cainet.info/git/cai/CAI-Watchdog/pulls/13
2022-07-01 12:12:53 +03:00
Alexander I. Chebykin
3976307952 Update README.md 2022-07-01 12:12:26 +03:00
2311ff28c9 Merge pull request 'Fixed some typos' (#12) from v1 into master
Reviewed-on: https://www.cainet.info/git/cai/CAI-Watchdog/pulls/12
2022-07-01 12:09:04 +03:00
Alexander I. Chebykin
48cc6af869 Fixed some typos
Fixed some typos
2022-07-01 12:06:57 +03:00
7feea8ccef Merge pull request 'Processes watching added' (#11) from v1 into master
Reviewed-on: https://www.cainet.info/git/cai/CAI-Watchdog/pulls/11
2022-06-30 00:02:45 +03:00
b638d510a3 Processes watching added
Processes watching added
2022-06-29 23:48:34 +03:00
7ad6b001eb Merge pull request 'Added unicode icons in messages' (#10) from v1 into master
Reviewed-on: https://www.cainet.info/git/cai/CAI-Watchdog/pulls/10
2022-06-29 01:41:40 +03:00
56d738bf8e Added unicode icons in messages
Added unicode icons in messages
2022-06-29 01:38:00 +03:00
171361480d Merge pull request 'README updated' (#9) from v1 into master
Reviewed-on: https://www.cainet.info/git/cai/CAI-Watchdog/pulls/9
2022-06-28 22:36:39 +03:00
2605fef9be README updated
README updated
2022-06-28 22:36:03 +03:00
08ff104659 Merge pull request 'v1' (#8) from v1 into master
Reviewed-on: https://www.cainet.info/git/cai/CAI-Watchdog/pulls/8
2022-06-28 22:34:01 +03:00
719562239a README updated
README updated
2022-06-28 22:32:49 +03:00
Alexander I. Chebykin
ff8c7bae7b Default values for settings added.
Default values for settings added. Print all services statuses on startup.
2022-06-28 18:22:37 +03:00
c3a572619f Merge pull request 'Minor changes.' (#7) from v1 into master
Reviewed-on: https://www.cainet.info/git/cai/CAI-Watchdog/pulls/7
2022-06-28 01:36:43 +03:00
7613ac88d9 Minor changes. 2022-06-28 01:36:02 +03:00
e7ca4cb434 Merge pull request '*nix send-mail script added.' (#6) from v1 into master
Reviewed-on: https://www.cainet.info/git/cai/CAI-Watchdog/pulls/6
2022-06-28 00:13:55 +03:00
486d9384cc *nix send-mail script added.
*nix send-mail script added. Scripts settings moved to config files
2022-06-28 00:13:07 +03:00
c981bfd033 Merge pull request 'Configuration file options modified.' (#5) from v1 into master
Reviewed-on: https://www.cainet.info/git/cai/CAI-Watchdog/pulls/5
2022-06-27 21:38:44 +03:00
b55f72f2e4 Configuration file options modified.
address renamed to uri, <header> renamed to <subject>
2022-06-27 21:37:11 +03:00
d406657bfb Merge pull request 'Notifications on program startup. Minor changes in scripts.' (#4) from v1 into master
Reviewed-on: https://www.cainet.info/git/cai/CAI-Watchdog/pulls/4
2022-06-27 18:15:55 +03:00
Alexander I. Chebykin
ccb471dcc2 Notifications on program startup. Minor changes in scripts.
Notifications on program startup. Minor changes in scripts.
2022-06-27 18:14:13 +03:00
2e2cf449a4 Merge pull request 'Minor changes in Windows scripts' (#3) from v1 into master
Reviewed-on: https://www.cainet.info/git/cai/CAI-Watchdog/pulls/3
2022-06-27 09:37:45 +03:00
Alexander I. Chebykin
577ad19b9f Minor changes in Windows scripts
Minor changes in Windows scripts
2022-06-27 09:35:30 +03:00
30a556f8f0 Merge pull request 'Configuration file teplate updated' (#2) from v1 into master
Reviewed-on: https://www.cainet.info/git/cai/CAI-Watchdog/pulls/2
2022-06-27 00:26:21 +03:00
024fe94ce9 Configuration file teplate updated
Configuration file teplate updated
2022-06-27 00:25:22 +03:00
3f96d27ee9 Merge pull request 'Minimal functionality implemented' (#1) from v1 into master
Reviewed-on: https://www.cainet.info/git/cai/CAI-Watchdog/pulls/1
2022-06-27 00:18:23 +03:00
e0011e421d Minimal functionality implemented
Minimal functionality implemented
2022-06-27 00:16:39 +03:00
32 changed files with 3575 additions and 2 deletions

12
.gitignore vendored Normal file
View File

@@ -0,0 +1,12 @@
# Editor directories and files
.idea
.vscode
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
# Build files
target
Cargo.lock

2080
Cargo.lock generated Normal file

File diff suppressed because it is too large Load Diff

20
Cargo.toml Normal file
View File

@@ -0,0 +1,20 @@
[package]
name = "cai-watchdog"
version = "0.9.0"
authors = ["Alexander I. Chebykin <alex.chebykin@gmail.com>"]
edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
file-utils = "0.1"
chrono = "0.4"
# Sync
#reqwest = { version = "0.11", features = ["blocking"] }
# Async
reqwest = "0.12"
tokio = { version = "1.43", features = ["full"] }
ini = "1.3"
exitcode = "1.1"
sysinfo = "0.33"
sys-locale = "0.3"

View File

@@ -1,6 +1,6 @@
MIT License MIT License
Copyright (c) <year> <copyright holders> Copyright (c) 2022 Alexander I. Chebykin <alex.chebykin@gmail.com>
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

182
README.md
View File

@@ -1,3 +1,183 @@
# CAI-Watchdog # CAI-Watchdog
Watchdog for monitoring web-services Watchdog for monitoring web-services and running processes
## Requirements
### On \*nix
- OpenSSL 1.0.1, 1.0.2, 1.1.0, or 1.1.1 with headers (see https://github.com/sfackler/rust-openssl)
- Perl
- Curl
### On Windows
- PowerShell
## Configuration file
Default configuration file location:
**On \*nix:** /etc/cai-watchdog.conf
**On Windows:** current directory
You can specify config file as parameter: ```cai-watchdog /path/to/config/config_file.conf``` (*nix) or ```cai-watchdog.exe drive:\path\to\config\config_file.ini``` (Windows)
### Configuration file parameters
```
[main]
check_interval = Interval between checks in seconds
rules_count = Rules count to be loaded from config. Rules sections must be enumerated continuously [rule1], [rule2] ... etc
on_start_command = Command to be executed when watchdog started
[rule1]
service = Service name
uri = URI to be checked
process = process to be checked
email = E-mail address for notifications
command = Command to send notification
```
In commands You can use fields ```<email>```, ```<subject>```, ```<message>```, ```<service>```, ```<uri>```, ```<process>``` and ```<state>```
- ```<email>``` - E-mail address for notifications
- ```<subject>``` - E-mail subject
- ```<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
#### *nix
##### send-mail
**Usage:** ```send-mail recipient 'subject' 'message'```
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-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
**Usage:** ```send-telegram 'message'```
Configuration file ```/etc/cai-watchdog/telegram.conf```
- ```Group ID:``` - Set Telegram group ID 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
##### send-mail.ps1
**Usage:** ```send-mail.ps1 recipient 'subject' 'message'```
Next lines needs to be configured:
- ```$EmailFrom = "yourmailadress@somedomain.com"``` - Set sender e-mail address here
- ```$SMTPServer = "smtp.somedomain.com"``` - Set SMTP-server address here
- ```$SMTPClient.EnableSsl = $true``` - Set SSL flag here
- ```$SMTPClient.Credentials = New-Object System.Net.NetworkCredential("usr", "pass");``` - Set user ("usr") and password ("pass") here
##### send-telegram.ps1
**Usage:** ```send-telegram.ps1 'message'```
- ```$Telegramtoken = "Your_Telegram_Token"``` - Set Telegram token here
- ```$Telegramchatid = "Your_Telegram_Chat_ID"``` - Set Telegram chat ID here
### How to get Telegram token and chat ID
1. Open ```@BotFather``` bot
1. Run ```/newbot``` command and give name to your new bot
1. Enter a username for the bot
1. Take note of the API token. We will need this later. **Note:** it is case sensitive
1. Click the link to open a chat with the newly created bot
Next you need to find your Telegram Chat ID.
1. From the Telegram home screen, search for ```chatid_echo_bot```. Click Chat ID Echo to open a chat
1. Enter ```/start``` to get the bot to send you your Telegram Chat ID
1. Take note of the Telegram Chat ID returned
### Service configuration (*nix)
If you want to get messages when watchdog service is stopped, uncomment following line: ```ExecStopPost=/etc/cai-watchdog/on-stop```
## User logins monitoring (*nix)
Watchdog can send notifications on user login. Just add to ```/etc/profile.d/sshinfo.sh``` next lines:
- For Telegram:
```
User=$(whoami)
IP=$(echo $SSH_CONNECTION | awk '{ print $1 == "" ? "127.0.0.1" : $1 }')
CAI_WATCHDOG_PATH=/etc/cai-watchdog
source ${CAI_WATCHDOG_PATH}/inc-icons
${CAI_WATCHDOG_PATH}/send-telegram "${ICON_INFO} SSH: User ${User} is logged in from ${IP}"
```
- For e-mail:
```
User=$(whoami)
IP=$(echo $SSH_CONNECTION | awk '{ print $1 == "" ? "127.0.0.1" : $1 }')
CAI_WATCHDOG_PATH=/etc/cai-watchdog
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}'
```
## User logouts monitoring (*nix)
1. Create file ```/etc/pam.d/pam_session.sh``` with next content:
For Telegram:
```
#!/bin/sh
CAI_WATCHDOG_PATH=/etc/cai-watchdog
if [ "$PAM_TYPE" = "close_session" ]; then
${CAI_WATCHDOG_PATH}/send-telegram "SSH: User ${PAM_USER} is logged out"
fi
```
For e-mail:
```
#!/bin/sh
CAI_WATCHDOG_PATH=/etc/cai-watchdog
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'
fi
```
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```
## 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.

View File

@@ -0,0 +1,25 @@
[main]
check_interval = 10
rules_count = 3
on_start_command = /etc/cai-watchdog/on-start
[rule1]
service = Test1
uri = http://127.0.0.1:3000/api/v1/
process =
email = admin@server.local
command = /etc/cai-watchdog/send-telegram <message>
[rule2]
service = Test2
uri = http://127.0.0.1:3300/api/v1/
process =
email = admin@server.local
command = /etc/cai-watchdog/send-telegram <message>
[rule3]
service = Apache
uri =
process = httpd
email = admin@server.local
command = /etc/cai-watchdog/send-telegram <message>

View File

@@ -0,0 +1,4 @@
Username: user@domain.local
Password: str0ngP@$$word
SMTP Server: smtp.domain.local
Port: 465

View File

@@ -0,0 +1,5 @@
#!/bin/bash
ICON_INFO=$(echo -e "\U2139")
ICON_WARNING=$(echo -e "\U26A0")
ICON_OK=$(echo -e "\U2705")
ICON_FAIL=$(echo -e "\U274C")

View File

@@ -0,0 +1,26 @@
[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 = Информация о версии

View File

@@ -0,0 +1,29 @@
#!/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"

View File

@@ -0,0 +1,11 @@
#!/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 is started!"

View File

@@ -0,0 +1,11 @@
#!/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 запущен!"

View File

@@ -0,0 +1,11 @@
#!/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} ATTENTION! Watchdog is stopped!"

View File

@@ -0,0 +1,11 @@
#!/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 остановлен!"

View File

@@ -0,0 +1,29 @@
#!/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"

View File

@@ -0,0 +1,49 @@
#!/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
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: '"${subj}"'
Date: '"$(date)"'
'"${message}"'
-----
'"${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

View File

@@ -0,0 +1,81 @@
#!/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

View File

@@ -0,0 +1,38 @@
#!/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
MESSAGE_TEXT=$1
if [ "$#" -ne 1 ]; then
echo "You can pass only one argument. For string with spaces put it on quotes"
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

View File

@@ -0,0 +1,65 @@
#!/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

View File

@@ -0,0 +1,2 @@
Group ID: Telegram_Group_ID
Bot token: Telegram_Bot_Token

View File

@@ -0,0 +1,17 @@
[Unit]
Description=Watchdog service
[Service]
User=wwwrun
Group=www
Type=simple
ExecStart=/usr/local/sbin/cai-watchdog
ExecStopPost=/etc/cai-watchdog/on-stop
KillMode=control-group
NotifyAccess=all
SuccessExitStatus=2
[Install]
WantedBy=multi-user.target
Alias=cai_watchdog

View File

@@ -0,0 +1,25 @@
[main]
check_interval = 10
rules_count = 3
on_start_command = ./on-start.ps1
[rule1]
service = Test1
uri = http://127.0.0.1:3000/api/v1/
process =
email = admin@server.local
command = ./send-telegram.ps1 <message>
[rule2]
service = Test2
uri = http://127.0.0.1:3300/api/v1/
process =
email = admin@server.local
command = ./send-telegram.ps1 <message>
[rule3]
service = Apache
uri =
process = httpd.exe
email = admin@server.local
command = ./send-telegram.ps1 <message>

View File

@@ -0,0 +1,26 @@
[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 = Информация о версии

View File

@@ -0,0 +1,9 @@
$EmailFrom = "yourmailadress@somedomain.com"
$EmailTo = $args[0]
$Subject = $args[1]
$Body = $args[0]
$SMTPServer = "smtp.somedomain.com"
$SMTPClient = New-Object Net.Mail.SmtpClient($SmtpServer, 587)
$SMTPClient.EnableSsl = $true
$SMTPClient.Credentials = New-Object System.Net.NetworkCredential("usr", "pass");
$SMTPClient.Send($EmailFrom, $EmailTo, $Subject, $Body)

View File

@@ -0,0 +1,8 @@
$Telegramtoken = "Your_Telegram_Token"
$Telegramchatid = "Your_Telegram_Chat_ID"
$Message = $args[0]
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
$Response = Invoke-RestMethod -Uri "https://api.telegram.org/bot$($Telegramtoken)/sendMessage?chat_id=$($Telegramchatid)&text=$($Message)"

291
src/main.rs Normal file
View File

@@ -0,0 +1,291 @@
//! CAI-Watchdog is a lightweigth watchdog for *nix and Windows
//! Author: Alexander I. Chebykin (CAI) <alex.chebykin@gmail.com>
#[macro_use]
extern crate ini;
extern crate exitcode;
use std::env;
use std::path::Path;
use std::thread;
use std::time::Duration;
mod mods;
use crate::mods::mod_debug::*;
use crate::mods::mod_fs::*;
use crate::mods::mod_i18n::*;
use crate::mods::mod_os::*;
use crate::mods::mod_tasks::*;
/// Check rule
///
/// # Arguments
///
/// * `rule` Rule to be checked
///
/// # Example
///
/// ```
/// if check(&tasks[i]).await {
/// println!("ok");
/// } else {
/// println!("uh-oh... something wrong!");
/// }
/// ```
async fn check(rule: &Rule) -> bool {
return if rule.uri.to_string() != "".to_string() {
check_uri(rule.uri.clone()).await
} else {
check_process(rule.process.clone())
};
}
/// Checks web-service availability
///
/// # Arguments
///
/// * `uri` - Service URI to be checked
///
/// # Example
///
/// ```
/// if check_uri("https://somesite.local/api/v1/".to_string()).await {
/// println!("ok");
/// } else {
/// println!("uh-oh... something wrong!");
/// }
/// ```
async fn check_uri(uri: String) -> bool {
if let Err(_e) = reqwest::get(uri).await {
return false;
} else {
return true;
}
}
/// Print help and program version information
///
/// # Arguments
///
/// * `args` - Command-line arguments
///
/// # Example
///
/// ```
/// let args: Vec<String> = env::args().collect();
///
/// print_help(args.clone());
/// ```
fn print_help(args: Vec<String>) {
let locale = Locale::new();
if cfg!(windows) {
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!("Usage: {} [/? | /help | /v | /ver | config_file]", &args[0]);
println!(" /? | /help : {}", locale.t().this_help_message);
println!(" /v | /ver : {}", locale.t().version_info);
println!(" config_file : {}", locale.t().configuration_file);
std::process::exit(exitcode::OK);
} else if args.len() > 1
&& (args[1].to_string() == "/ver".to_string() || args[1].to_string() == "/v".to_string()) {
const VERSION: &str = env!("CARGO_PKG_VERSION");
println!("CAI Watchdog {} {}", locale.t().ver, VERSION);
std::process::exit(exitcode::OK);
}
} else {
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!("{}: {} [-h | --help | -v | --ver | config_file]", locale.t().usage, &args[0]);
println!(" -h | --help : {}", locale.t().this_help_message);
println!(" -v | --ver : {}", locale.t().version_info);
println!(" config_file : {}", locale.t().configuration_file);
std::process::exit(exitcode::OK);
} else if args.len() > 1
&& (args[1].to_string() == "--ver".to_string() || args[1].to_string() == "-v".to_string()) {
const VERSION: &str = env!("CARGO_PKG_VERSION");
println!("CAI Watchdog {} {}", locale.t().ver, VERSION);
std::process::exit(exitcode::OK);
}
}
}
fn main() {
let locale = Locale::new();
let args: Vec<String> = env::args().collect();
print_help(args.clone());
let mut config_file = get_exe_path();
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 {
&args[1]
} else {
&config_file
};
if !Path::new(cfg_file).exists() {
println!("\u{26a0} {}! {}.",
locale.t().error,
locale.t().cant_find_config_file
);
println!("{}", locale.t().exiting);
std::process::exit(exitcode::CONFIG);
}
let cfg = ini!(cfg_file);
let check_interval = if cfg["main"].contains_key("check_interval") {
cfg["main"]["check_interval"].clone().unwrap().parse::<u64>().unwrap() * 1000
} else {
10000
};
let rules_count = if cfg["main"].contains_key("check_interval") {
cfg["main"]["rules_count"].clone().unwrap().parse::<u8>().unwrap()
} else {
0
};
let mut tasks_prc = vec![];
let mut tasks_web = vec![];
for i in 1..rules_count + 1 {
let service = if cfg[&format!("rule{}", i)].contains_key("service") {
cfg[&format!("rule{}", i)]["service"].clone().unwrap()
} else {
format!("Service {}", i)
};
let uri = if cfg[&format!("rule{}", i)].contains_key("uri") {
cfg[&format!("rule{}", i)]["uri"].clone().unwrap()
} else {
"".to_string()
};
let process = if cfg[&format!("rule{}", i)].contains_key("process") {
cfg[&format!("rule{}", i)]["process"].clone().unwrap()
} else {
"".to_string()
};
let email = if cfg[&format!("rule{}", i)].contains_key("email") {
cfg[&format!("rule{}", i)]["email"].clone().unwrap()
} else {
"".to_string()
};
let command = if cfg[&format!("rule{}", i)].contains_key("command") {
cfg[&format!("rule{}", i)]["command"].clone().unwrap()
} else {
"".to_string()
};
debug_log(format!("rule {}", i));
debug_log(format!("service {}", service));
debug_log(format!("uri {}", uri));
debug_log(format!("process {}", process));
debug_log(format!("email {}", email));
debug_log(format!("command {}", command));
if uri != "".to_string() {
tasks_web.push(
Rule{
service: service,
uri: uri,
process: process,
email: email,
command: command,
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") {
cfg["main"]["on_start_command"].clone().unwrap()
} else {
"".to_string()
};
debug_log(format!("\u{2139} {}", locale.t().service_started));
if on_start_command.to_string() != "" {
execute(on_start_command);
}
let mut just_started_web = true;
std::thread::spawn(move || {
loop {
for i in 0..tasks_web.len() {
let rt = tokio::runtime::Runtime::new().unwrap();
rt.block_on(async {
if check(&tasks_web[i]).await {
execute_web_task(&mut tasks_web[i], true, just_started_web);
} else {
execute_web_task(&mut tasks_web[i], false, just_started_web);
}
});
}
just_started_web = false;
thread::sleep(Duration::from_millis(check_interval));
}
});
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 {
execute_os_task(&mut tasks_prc[i], false, just_started_prc);
}
});
}
just_started_prc = false;
thread::sleep(Duration::from_millis(check_interval));
}
}

5
src/mods/mod.rs Normal file
View File

@@ -0,0 +1,5 @@
pub mod mod_debug;
pub mod mod_fs;
pub mod mod_i18n;
pub mod mod_os;
pub mod mod_tasks;

16
src/mods/mod_debug.rs Normal file
View File

@@ -0,0 +1,16 @@
/// 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);
}
}

26
src/mods/mod_fs.rs Normal file
View File

@@ -0,0 +1,26 @@
//! 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;
}

185
src/mods/mod_i18n.rs Normal file
View File

@@ -0,0 +1,185 @@
//! 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();
}
}

70
src/mods/mod_os.rs Normal file
View File

@@ -0,0 +1,70 @@
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));
}

206
src/mods/mod_tasks.rs Normal file
View File

@@ -0,0 +1,206 @@
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;
}