Minimal functionality implemented
Minimal functionality implemented
This commit is contained in:
parent
239197ffed
commit
e0011e421d
11
.gitignore
vendored
Normal file
11
.gitignore
vendored
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
# Editor directories and files
|
||||||
|
.idea
|
||||||
|
.vscode
|
||||||
|
*.suo
|
||||||
|
*.ntvs*
|
||||||
|
*.njsproj
|
||||||
|
*.sln
|
||||||
|
*.sw?
|
||||||
|
|
||||||
|
# Build files
|
||||||
|
target
|
||||||
1083
Cargo.lock
generated
Normal file
1083
Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
17
Cargo.toml
Normal file
17
Cargo.toml
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
[package]
|
||||||
|
name = "cai-watchdog"
|
||||||
|
version = "0.1.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.5"
|
||||||
|
chrono = "0.4.19"
|
||||||
|
# Sync
|
||||||
|
#reqwest = { version = "0.11", features = ["blocking"] }
|
||||||
|
# Async
|
||||||
|
reqwest = "0.11"
|
||||||
|
tokio = { version = "1", features = ["full"] }
|
||||||
|
ini = "1.3.0"
|
||||||
2
LICENSE
2
LICENSE
@ -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:
|
||||||
|
|
||||||
|
|||||||
9
scripts/cai-watchdog.cfg.template
Normal file
9
scripts/cai-watchdog.cfg.template
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
[main]
|
||||||
|
check_interval = 10000
|
||||||
|
rules_count = 2
|
||||||
|
[rule1]
|
||||||
|
address = http://127.0.0.1:3000/api/v1/
|
||||||
|
email = admin@server.local
|
||||||
|
[rule2]
|
||||||
|
address = http://127.0.0.1:3300/api/v1/
|
||||||
|
email = admin@server.local
|
||||||
16
scripts/unix/cai-watchdog.service.template
Normal file
16
scripts/unix/cai-watchdog.service.template
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=Watchdog service
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
User=wwwrun
|
||||||
|
Group=www
|
||||||
|
Type=simple
|
||||||
|
ExecStart=/usr/local/bin/cai-watchdog
|
||||||
|
|
||||||
|
KillMode=control-group
|
||||||
|
NotifyAccess=all
|
||||||
|
SuccessExitStatus=2
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
|
Alias=cai_watchdog
|
||||||
23
scripts/unix/send-telegram.template
Normal file
23
scripts/unix/send-telegram.template
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
GROUP_ID=<group_id>
|
||||||
|
BOT_TOKEN=<bot_token>
|
||||||
|
|
||||||
|
# this 3 checks (if) are not necessary but should be convenient
|
||||||
|
if [ "$1" == "-h" ]; then
|
||||||
|
echo "Usage: `basename $0` \"text message\""
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z "$1" ]
|
||||||
|
then
|
||||||
|
echo "Add message text as second arguments"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$#" -ne 1 ]; then
|
||||||
|
echo "You can pass only one argument. For string with spaces put it on quotes"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
curl -s --data "text=$1" --data "chat_id=$GROUP_ID" 'https://api.telegram.org/bot'$BOT_TOKEN'/sendMessage' > /dev/null
|
||||||
11
scripts/windowss/send-mail.ps1.template
Normal file
11
scripts/windowss/send-mail.ps1.template
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
Function Send-Mail {
|
||||||
|
$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)
|
||||||
|
}
|
||||||
10
scripts/windowss/send-telegram.ps1.template
Normal file
10
scripts/windowss/send-telegram.ps1.template
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
Function Send-Telegram {
|
||||||
|
Param([Parameter(Mandatory=$true)][String]$Message)
|
||||||
|
|
||||||
|
$Telegramtoken = "Your_Telegram_Token"
|
||||||
|
$Telegramchatid = "Your_Telegram_Chat_ID"
|
||||||
|
|
||||||
|
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
|
||||||
|
|
||||||
|
$Response = Invoke-RestMethod -Uri "https://api.telegram.org/bot$($Telegramtoken)/sendMessage?chat_id=$($Telegramchatid)&text=$($Message)"
|
||||||
|
}
|
||||||
176
src/main.rs
Normal file
176
src/main.rs
Normal file
@ -0,0 +1,176 @@
|
|||||||
|
#[macro_use]
|
||||||
|
extern crate ini;
|
||||||
|
|
||||||
|
use std::thread;
|
||||||
|
use std::time::Duration;
|
||||||
|
use std::process::Command;
|
||||||
|
|
||||||
|
/// Rule description structure
|
||||||
|
pub struct Rule {
|
||||||
|
/// Monitored service name
|
||||||
|
pub service: String,
|
||||||
|
/// Monitored URI
|
||||||
|
pub address: 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,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Checks service availability
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
///
|
||||||
|
/// * `uri` - Service URI to be checked
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// if if check("https://somesite.local/api/v1/".to_string()).await {
|
||||||
|
/// println!("ok");
|
||||||
|
/// } else {
|
||||||
|
/// println!("uh-oh... something wrong!");
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
async fn check(uri: String) -> bool {
|
||||||
|
if let Err(_e) = reqwest::get(uri).await {
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 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));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let cfg_file = if cfg!(windows) {
|
||||||
|
"cai-watchdog.cfg"
|
||||||
|
} else {
|
||||||
|
"/etc/cai-watchdog.cfg"
|
||||||
|
};
|
||||||
|
|
||||||
|
let cfg = ini!(cfg_file);
|
||||||
|
|
||||||
|
let check_interval = cfg["main"]["check_interval"].clone().unwrap().parse::<u64>().unwrap();
|
||||||
|
let rules_count = cfg["main"]["rules_count"].clone().unwrap().parse::<u8>().unwrap();
|
||||||
|
|
||||||
|
let mut tasks = vec![];
|
||||||
|
|
||||||
|
for i in 1..rules_count + 1 {
|
||||||
|
let service = cfg[&format!("{}{}", "rule", i)]["service"].clone().unwrap();
|
||||||
|
let address = cfg[&format!("{}{}", "rule", i)]["address"].clone().unwrap();
|
||||||
|
let email = cfg[&format!("{}{}", "rule", i)]["email"].clone().unwrap();
|
||||||
|
let command = cfg[&format!("{}{}", "rule", i)]["command"].clone().unwrap();
|
||||||
|
|
||||||
|
debug_log(format!("rule {}", i));
|
||||||
|
debug_log(format!("service {}", service));
|
||||||
|
debug_log(format!("address {}", address));
|
||||||
|
debug_log(format!("email {}", email));
|
||||||
|
debug_log(format!("command {}", command));
|
||||||
|
|
||||||
|
tasks.push(
|
||||||
|
Rule{
|
||||||
|
service: cfg[&format!("{}{}", "rule", i)]["service"].clone().unwrap().to_string(),
|
||||||
|
address: cfg[&format!("{}{}", "rule", i)]["address"].clone().unwrap().to_string(),
|
||||||
|
email: cfg[&format!("{}{}", "rule", i)]["email"].clone().unwrap().to_string(),
|
||||||
|
command: cfg[&format!("{}{}", "rule", i)]["command"].clone().unwrap().to_string(),
|
||||||
|
last_state: false,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
loop {
|
||||||
|
for i in 0..tasks.len() {
|
||||||
|
let rt = tokio::runtime::Runtime::new().unwrap();
|
||||||
|
rt.block_on(async {
|
||||||
|
if check(tasks[i].address.clone()).await {
|
||||||
|
if tasks[i].last_state != true {
|
||||||
|
debug_log(format!("{} state changed to true", tasks[i].address));
|
||||||
|
|
||||||
|
let shell_cmd = tasks[i].command.to_string()
|
||||||
|
.replace("<email>", &tasks[i].email)
|
||||||
|
.replace("<header>", &format!("\"Service {} ({}) online\"", tasks[i].service, tasks[i].address))
|
||||||
|
.replace("<message>", &format!("\"Service {} ({}) is now online\"", tasks[i].service, tasks[i].address));
|
||||||
|
|
||||||
|
debug_log(format!("execute {}", shell_cmd));
|
||||||
|
|
||||||
|
execute(shell_cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
debug_log(format!("{} check is ok", tasks[i].address));
|
||||||
|
|
||||||
|
tasks[i].last_state = true
|
||||||
|
} else {
|
||||||
|
if tasks[i].last_state != false {
|
||||||
|
debug_log(format!("{} state changed to false", tasks[i].address));
|
||||||
|
|
||||||
|
let shell_cmd = tasks[i].command.to_string()
|
||||||
|
.replace("<email>", &tasks[i].email)
|
||||||
|
.replace("<header>", &format!("\"Service {} ({}) offline\"", tasks[i].service, tasks[i].address))
|
||||||
|
.replace("<message>", &format!("\"Service {} ({}) is now offline\"", tasks[i].service, tasks[i].address));
|
||||||
|
|
||||||
|
debug_log(format!("execute {}", shell_cmd));
|
||||||
|
execute(shell_cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
debug_log(format!("{} check failed", tasks[i].address));
|
||||||
|
|
||||||
|
tasks[i].last_state = false
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
thread::sleep(Duration::from_millis(check_interval));
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user