From 1f460ae94d23a8222173dca42984134a8cc2ecb8 Mon Sep 17 00:00:00 2001 From: isaidsari Date: Tue, 21 May 2024 00:08:45 +0300 Subject: [PATCH 1/2] feat: add api endpoint for killing a process --- src/api.rs | 1 + src/api/get_processes.rs | 13 +++--- src/api/kill_process.rs | 88 ++++++++++++++++++++++++++++++++++++++++ src/logger.rs | 4 -- src/main.rs | 1 + src/monitor.rs | 78 +++++++++++++++-------------------- 6 files changed, 129 insertions(+), 56 deletions(-) create mode 100644 src/api/kill_process.rs diff --git a/src/api.rs b/src/api.rs index df80968..67acbb8 100644 --- a/src/api.rs +++ b/src/api.rs @@ -14,6 +14,7 @@ pub mod teapot; pub mod update_info; pub mod validate_token_test; pub mod get_processes; +pub mod kill_process; use serde::{Deserialize, Serialize}; diff --git a/src/api/get_processes.rs b/src/api/get_processes.rs index c3e3de0..43bf7b2 100644 --- a/src/api/get_processes.rs +++ b/src/api/get_processes.rs @@ -2,10 +2,7 @@ use hyper::{Body, Request, Response}; use log::debug; use std::convert::Infallible; -use crate::{ - api::{authenticate, ResponseBody}, - monitor::get_process_list, -}; +use crate::{api::authenticate, monitor::get_process_list}; pub async fn get_processes(req: Request) -> Result, Infallible> { match authenticate(&req) { @@ -16,8 +13,12 @@ pub async fn get_processes(req: Request) -> Result, Infalli }; let start = std::time::Instant::now(); - let processes = get_process_list(); - debug!("get_processes[{}] took: {:?}",processes.len(), start.elapsed()); + let processes = get_process_list().await; + debug!( + "get_processes[{}] took: {:?}", + processes.len(), + start.elapsed() + ); let response = Response::builder() .status(hyper::StatusCode::OK) diff --git a/src/api/kill_process.rs b/src/api/kill_process.rs new file mode 100644 index 0000000..5bbff8e --- /dev/null +++ b/src/api/kill_process.rs @@ -0,0 +1,88 @@ +use hyper::{Body, Request, Response}; +use log::debug; +use std::convert::Infallible; + +use crate::{ + api::{authenticate, ResponseBody}, + monitor, +}; + +pub async fn kill_process(req: Request) -> Result, Infallible> { + match authenticate(&req) { + Ok(val) => val, + Err(err) => { + return Ok(err); + } + }; + + // extract pid from query params + let query_str = match req.uri().query() { + Some(q) => q, + None => { + let response = Response::builder() + .status(hyper::StatusCode::BAD_REQUEST) + .header("Content-Type", "application/json") + .body(Body::from( + serde_json::to_string(&ResponseBody::Error("The query parameters are missing.".to_string())) + .unwrap(), + )) + .unwrap(); + return Ok(response); + } + }; + let query_params: Vec<&str> = query_str.split("&").collect(); + let pid = match query_params[0].split("=").collect::>().get(1) { + Some(p) => match p.parse::() { + Ok(pid) => pid, + Err(_) => { + let response = Response::builder() + .status(hyper::StatusCode::BAD_REQUEST) + .header("Content-Type", "application/json") + .body(Body::from( + serde_json::to_string(&ResponseBody::Error("Query paramter parse error.".to_string())) + .unwrap(), + )) + .unwrap(); + return Ok(response); + } + }, + None => { + let response = Response::builder() + .status(hyper::StatusCode::BAD_REQUEST) + .header("Content-Type", "application/json") + .body(Body::from( + serde_json::to_string(&ResponseBody::Error("Invalid query parameters.".to_string())) + .unwrap(), + )) + .unwrap(); + return Ok(response); + } + + }; + + match monitor::kill_process(pid).await { + Ok(_) => { + debug!("Process {} killed successfully", pid); + let response = Response::builder() + .status(hyper::StatusCode::OK) + .header("Content-Type", "application/json") + .body(Body::from( + serde_json::to_string(&ResponseBody::Success(true)).unwrap(), + )) + .unwrap(); + Ok(response) + } + Err(err) => { + debug!("Error killing process: {}", err); + let response = Response::builder() + .status(hyper::StatusCode::INTERNAL_SERVER_ERROR) + .header("Content-Type", "application/json") + .body(Body::from( + serde_json::to_string(&ResponseBody::Error(err.to_string())) + .unwrap(), + )) + .unwrap(); + Ok(response) + } + } +} diff --git a/src/logger.rs b/src/logger.rs index 33f4e76..c698b69 100644 --- a/src/logger.rs +++ b/src/logger.rs @@ -33,10 +33,6 @@ impl Write for CustomPipe { let log_parts: Vec<&str> = log_str.splitn(4, " ").collect(); let log_level = log_parts[2]; - io::stdout() - .write_all(format!("{:?}\n", log_level).as_bytes()) - .unwrap(); - let app_log = AppLog { id: -1, log_level: LogLevel::from_string(log_level), diff --git a/src/main.rs b/src/main.rs index 45e615a..5f0b5cd 100644 --- a/src/main.rs +++ b/src/main.rs @@ -70,6 +70,7 @@ async fn req_handler(req: Request) -> Result, Infallible> { (&Method::GET, "/get-mem-status") => api::get_mem_status::get_mem_status(req).await, (&Method::GET, "/get-disk-status") => api::get_disk_status::get_disk_status(req).await, (&Method::GET, "/get-processes") => api::get_processes::get_processes(req).await, + (&Method::GET, "/kill-process") => api::kill_process::kill_process(req).await, (&Method::GET, "/validate-token-test") => { api::validate_token_test::validate_token_test(req).await } diff --git a/src/monitor.rs b/src/monitor.rs index 7f8fd4a..4a5ce9f 100644 --- a/src/monitor.rs +++ b/src/monitor.rs @@ -1,9 +1,7 @@ use self::models::{ProcessInfo, ServerDescription}; -use log::debug; -use sysinfo::{CpuRefreshKind, ProcessRefreshKind, RefreshKind, System}; - -use std::time::Instant; +use log::{debug, error}; +use sysinfo::{CpuRefreshKind, Pid, ProcessRefreshKind, RefreshKind, System}; mod config_exceeds; pub mod models; @@ -38,8 +36,8 @@ pub fn get_default_server_desc() -> ServerDescription { ServerDescription { name, description } } -pub fn get_process_list() -> Vec { - let system = System::new_with_specifics( +pub async fn get_process_list() -> Vec { + let mut system = System::new_with_specifics( RefreshKind::new().with_processes( ProcessRefreshKind::new() .with_cpu() @@ -48,6 +46,11 @@ pub fn get_process_list() -> Vec { ), ); + system.refresh_processes(); + // wait for a while to get the updated process list + tokio::time::sleep(sysinfo::MINIMUM_CPU_UPDATE_INTERVAL).await; + system.refresh_processes(); + let mut processes = Vec::new(); for (pid, process) in system.processes() { processes.push(models::ProcessInfo { @@ -60,48 +63,31 @@ pub fn get_process_list() -> Vec { }); } - processes -} - -// for testing -fn get_process_list_wmetrics() -> Vec { - let start_total_time = Instant::now(); + // sort list descending order by cpu and return + processes.sort_by(|a, b| b.cpu.partial_cmp(&a.cpu).unwrap()); - // Timing metrics for fetching process information - let start_process_time = Instant::now(); - let system = System::new_with_specifics( - RefreshKind::new().with_processes( - ProcessRefreshKind::new() - .with_cpu() - .with_memory() - .with_cmd(sysinfo::UpdateKind::Always), - ), - ); - let process_time = start_process_time.elapsed(); + return processes; +} - // Timing metrics for processing process information - let start_process_processing_time = Instant::now(); - let mut processes = Vec::new(); - for (pid, process) in system.processes() { - processes.push(models::ProcessInfo { - pid: pid.as_u32(), - name: process.name().to_string(), - cpu: process.cpu_usage(), - mem: process.memory(), - status: process.status().to_string(), - cmd: process.cmd().to_vec(), - }); +pub async fn kill_process(pid: u32) -> Result<(), String> { + let system = + System::new_with_specifics(RefreshKind::new().with_processes(ProcessRefreshKind::new())); + + let process = system.process(Pid::from_u32(pid)); + + match process { + Some(process) => { + debug!("Killing process with pid {} , name {}", process.pid(), process.name()); + let success = process.kill(); + if success { + debug!("Process with pid {} killed successfully", pid); + Ok(()) + } else { + error!("Failed to kill process with pid {}", pid); + Err(format!("Failed to kill process with pid {}", pid)) + } + } + None => Err(format!("Process with pid {} not found", pid)), } - let process_processing_time = start_process_processing_time.elapsed(); - - let total_time = start_total_time.elapsed(); - - debug!("get_process_list took: {:?}", total_time); - debug!("get_process_list process took: {:?}", process_time); - debug!( - "get_process_list process processing took: {:?}", - process_processing_time - ); - processes } From c69b1ba2c095f14bad2ef2fcbcd72c52a26bc286 Mon Sep 17 00:00:00 2001 From: isaidsari Date: Tue, 21 May 2024 01:44:40 +0300 Subject: [PATCH 2/2] conflict resolved --- CHANGELOG.md | 8 +++++++- Cargo.toml | 2 +- src/api/get_processes.rs | 9 +++++++-- 3 files changed, 15 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2c2a7b4..97a0f00 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,13 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), -## [Unreleased] - 19-04-2024 +## [0.1.2] + +### Added + +- v0.1.2 kill process added + +## [0.1.1] ### Added diff --git a/Cargo.toml b/Cargo.toml index 2d68ab6..3e1b111 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "remon-server" -version = "0.1.1" +version = "0.1.2" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/src/api/get_processes.rs b/src/api/get_processes.rs index 7aae788..9a3ef4b 100644 --- a/src/api/get_processes.rs +++ b/src/api/get_processes.rs @@ -3,7 +3,10 @@ use log::debug; use serde::Serialize; use std::convert::Infallible; -use crate::{api::authenticate, monitor::get_process_list}; +use crate::{ + api::authenticate, + monitor::{get_process_list, models::ProcessInfo}, +}; #[derive(Serialize)] struct ResponseData { @@ -29,7 +32,9 @@ pub async fn get_processes(req: Request) -> Result, Infalli let response = Response::builder() .status(hyper::StatusCode::OK) .header("Content-Type", "application/json") - .body(Body::from(serde_json::to_string(&processes).unwrap())) + .body(Body::from( + serde_json::to_string(&ResponseData { processes }).unwrap(), + )) .unwrap(); Ok(response)