pull/9/head
prplV 2024-06-27 17:17:36 -04:00
commit e232cf29ca
6 changed files with 263 additions and 0 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/target

89
Cargo.lock generated Normal file
View File

@ -0,0 +1,89 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "itoa"
version = "1.0.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b"
[[package]]
name = "proc-macro2"
version = "1.0.86"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.36"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7"
dependencies = [
"proc-macro2",
]
[[package]]
name = "runner-rs"
version = "0.1.0"
dependencies = [
"serde",
"serde_json",
]
[[package]]
name = "ryu"
version = "1.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f"
[[package]]
name = "serde"
version = "1.0.203"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7253ab4de971e72fb7be983802300c30b5a7f0c2e56fab8abfc6a214307c0094"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.203"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "500cbc0ebeb6f46627f50f3f5811ccf6bf00643be300b4c3eabc0ef55dc5b5ba"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "serde_json"
version = "1.0.118"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d947f6b3163d8857ea16c4fa0dd4840d52f3041039a85decd46867eb1abef2e4"
dependencies = [
"itoa",
"ryu",
"serde",
]
[[package]]
name = "syn"
version = "2.0.68"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "901fa70d88b9d6c98022e23b4136f9f3e54e4662c3bc1bd1d84a42a9a0f0c1e9"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "unicode-ident"
version = "1.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"

8
Cargo.toml Normal file
View File

@ -0,0 +1,8 @@
[package]
name = "runner-rs"
version = "0.1.0"
edition = "2021"
[dependencies]
serde = { version = "1.0.203", features = ["derive"] }
serde_json = "1.0.118"

13
service-checker.sh Normal file
View File

@ -0,0 +1,13 @@
#!/bin/bash
hostname=$1
port=$2
if nc -z -w1 $hostname $port > /dev/null 2>&1; then
echo "Service $hostname:$port is running"
exit 0
else
echo "Service $hostname:$port is unreachable"
exit 1
fi

22
settings.json Normal file
View File

@ -0,0 +1,22 @@
{
"processes" : [{
"name" : "web-server",
"path" : "/home/vladislav/web/web-server",
"dependencies" : {
"files" : [
{
"filename" : "control-file",
"src" : "/home/vladislav/web/"
},
{
"filename" : "config-file",
"src" : "/home/vladislav/web/"
}
],
"services" : [{
"hostname" : "ya.ru",
"port" : 443
}]
}
}]
}

130
src/main.rs Normal file
View File

@ -0,0 +1,130 @@
use serde::{Deserialize, Serialize};
use serde_json::{self, error};
use std::fs;
use std::path::Path;
use std::process::Command;
enum CustomError {
Fatal,
}
#[derive(Debug, Serialize, Deserialize)]
struct Processes {
#[serde(default)]
processes : Vec<TrackingProcess>,
}
#[derive(Debug, Serialize, Deserialize)]
struct TrackingProcess {
name : String,
path : String,
dependencies: Dependencies,
}
#[derive(Debug, Serialize, Deserialize)]
struct Dependencies {
#[serde(default)]
files : Vec<Files>,
#[serde(default)]
services: Vec<Services>,
}
#[derive(Debug, Serialize, Deserialize)]
struct Files {
filename : String,
src : String,
}
#[derive(Debug, Serialize, Deserialize)]
struct Services {
hostname : String,
port : u32,
}
fn main() {
let processes = load_processes("settings.json");
let mut error_counter = 0;
if processes.processes.len() == 0 {
eprintln!("Error: Processes list is null, runner-rs initialization is stopped");
return;
}
processes.processes.iter().for_each(|proc| {
println!("\nProcess '{}' on stage:\n{}\nDepends on {} file(s), {} service(s)\n",
proc.name,
proc.path,
proc.dependencies.files.len(),
proc.dependencies.services.len());
proc.dependencies.files.iter().for_each(|file| {
if let Err(_) = check_file(&file.filename, &file.src) {
println!("Error: Process {} cannot run without file {}{}", proc.name, file.src, file.filename);
error_counter += 1;
}
});
proc.dependencies.services.iter().for_each(|ser| {
if let Err(_) = check_service(&ser.hostname, &ser.port) {
println!("Error: Process {} cannot run while service {}:{} is down", proc.name, ser.hostname, ser.port);
error_counter += 1;
}
});
if (error_counter > 0) {
return;
}
match start_process(&proc.name, &proc.path) {
Ok(_) => {
println!("Success!");
},
Err(_) => {
println!("Error: Cannot run process");
},
}
return;
});
}
fn load_processes(json_filename: &str) -> Processes{
let read = fs::read_to_string(json_filename).expect(format!("Missing '{}' file. Cannot start runner", json_filename).as_str());
serde_json::from_str::<Processes>(&read).expect(format!("Parsing error in '{}' file. Cannot start runner", json_filename).as_str())
}
fn start_process(name: &str, path: &str) -> Result<(), CustomError> {
let runsh = format!("{}{}", path, "/run.sh");
let mut command = Command::new("bash");
command.arg(runsh);
match command.spawn() {
Ok(mut child) => {
println!("Process {} is running now!", name);
child.wait();
return Ok(());
},
Err(_) => return Err(CustomError::Fatal),
}
}
fn check_file(filename: &str, path: &str) -> Result<(), CustomError> {
let fileconcat = format!("{}{}", path, filename);
let path = Path::new(&fileconcat);
if path.exists() {
Ok(())
} else {
Err(CustomError::Fatal)
}
}
fn check_service(host: &str, port: &u32) -> Result<(), CustomError> {
let mut command = Command::new("bash");
command.args(["service-checker.sh", host, &port.to_string()]);
match command.output() {
Ok(output) => {
if (output.status.success()) {
return Ok(());
} else {
return Err(CustomError::Fatal);
}
},
Err(_) => {
return Err(CustomError::Fatal);
},
};
}