Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add kill_process api #23

Merged
merged 3 commits into from
May 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -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
Expand Down
1 change: 1 addition & 0 deletions src/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ pub mod teapot;
pub mod update_info;
pub mod validate_token_test;
pub mod get_processes;
pub mod kill_process;

pub mod logs {
pub mod get_app_ids;
Expand Down
8 changes: 4 additions & 4 deletions src/api/get_processes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,19 +22,19 @@ pub async fn get_processes(req: Request<Body>) -> Result<Response<Body>, Infalli
};

let start = std::time::Instant::now();
let processes = get_process_list();
let processes = get_process_list().await;
debug!(
"get_processes[{}] took: {:?}",
processes.len(),
start.elapsed()
);

let res = ResponseData { processes };

let response = Response::builder()
.status(hyper::StatusCode::OK)
.header("Content-Type", "application/json")
.body(Body::from(serde_json::to_string(&res).unwrap()))
.body(Body::from(
serde_json::to_string(&ResponseData { processes }).unwrap(),
))
.unwrap();

Ok(response)
Expand Down
88 changes: 88 additions & 0 deletions src/api/kill_process.rs
Original file line number Diff line number Diff line change
@@ -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<Body>) -> Result<Response<Body>, 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::<Vec<&str>>().get(1) {
Some(p) => match p.parse::<u32>() {
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)
}
}
}
4 changes: 0 additions & 4 deletions src/logger.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,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),
Expand Down
1 change: 1 addition & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ async fn req_handler(req: Request<Body>) -> Result<Response<Body>, 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
}
Expand Down
83 changes: 35 additions & 48 deletions src/monitor.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use self::models::{ProcessInfo, ServerDescription};

use log::debug;
use sysinfo::{CpuRefreshKind, ProcessRefreshKind, RefreshKind, System};
use log::{debug, error};
use sysinfo::{CpuRefreshKind, Pid, ProcessRefreshKind, RefreshKind, System};

mod config_exceeds;
pub mod models;
Expand Down Expand Up @@ -36,8 +36,8 @@ pub fn get_default_server_desc() -> ServerDescription {
ServerDescription { name, description }
}

pub fn get_process_list() -> Vec<ProcessInfo> {
let system = System::new_with_specifics(
pub async fn get_process_list() -> Vec<ProcessInfo> {
let mut system = System::new_with_specifics(
RefreshKind::new().with_processes(
ProcessRefreshKind::new()
.with_cpu()
Expand All @@ -46,6 +46,11 @@ pub fn get_process_list() -> Vec<ProcessInfo> {
),
);

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 {
Expand All @@ -58,49 +63,31 @@ pub fn get_process_list() -> Vec<ProcessInfo> {
});
}

processes
// sort list descending order by cpu and return
processes.sort_by(|a, b| b.cpu.partial_cmp(&a.cpu).unwrap());

return processes;
}

// for testing
// TODO(isaidsari): use this in a test
// fn get_process_list_wmetrics() -> Vec<models::ProcessInfo> {
// let start_total_time = Instant::now();

// // 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();

// // 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(),
// });
// }
// 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
// }
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)),
}

}
Loading