Skip to content

Commit

Permalink
teliod: Add command for daemon graceful shutdown
Browse files Browse the repository at this point in the history
  • Loading branch information
lcruz99 committed Dec 23, 2024
1 parent 030a443 commit 284a1bc
Show file tree
Hide file tree
Showing 4 changed files with 34 additions and 56 deletions.
12 changes: 12 additions & 0 deletions clis/teliod/src/command_listener.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,18 @@ impl CommandListener {
})
.await
}
ClientCmd::QuitDaemon =>
{
#[allow(mpsc_blocking_send)]
self.telio_task_tx
.send(TelioTaskCmd::Quit)
.await
.map(|_| CommandResponse::Ok)
.map_err(|e| {
error!("Error sending command: {}", e);
TeliodError::CommandFailed(ClientCmd::QuitDaemon)
})
}
}
}

Expand Down
4 changes: 4 additions & 0 deletions clis/teliod/src/daemon.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ use tokio::{sync::mpsc, sync::oneshot, time::Duration};
use tracing::{debug, error, info, trace};

use crate::core_api::{get_meshmap as get_meshmap_from_server, init_with_api};
use crate::ClientCmd;
use crate::{
command_listener::CommandListener,
comms::DaemonSocket,
Expand Down Expand Up @@ -254,6 +255,9 @@ pub async fn daemon_event_loop(config: TeliodDaemonConfig) -> Result<(), TeliodE
match result {
Ok(command) => {
info!("Client command {:?} executed successfully", command);
if command == ClientCmd::QuitDaemon {
break Ok(())
}
}
Err(err) => {
error!("Received invalid command from client: {}", err);
Expand Down
4 changes: 2 additions & 2 deletions clis/teliod/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ const TIMEOUT_SEC: u64 = 1;
enum ClientCmd {
#[clap(about = "Retrieve the status report")]
GetStatus,
#[clap(about = "Stop daemon execution")]
QuitDaemon,
}

#[derive(Parser, Debug)]
Expand Down Expand Up @@ -101,8 +103,6 @@ async fn main() -> Result<(), TeliodError> {
if DaemonSocket::get_ipc_socket_path()?.exists() {
Err(TeliodError::DaemonIsRunning)
} else {
#[cfg(feature = "qnap")]
let _pid_guard = qnap::PidFile::new().await?;
let file = File::open(&config_path)?;

let mut config: TeliodDaemonConfig = serde_json::from_reader(file)?;
Expand Down
70 changes: 16 additions & 54 deletions clis/teliod/src/qnap.rs
Original file line number Diff line number Diff line change
@@ -1,22 +1,19 @@
use core::str;
use std::{
fs::{self, OpenOptions},
io::{self, Write},
process::{self, Command, Stdio},
fs,
io::Write,
process::{Command, Stdio},
};

use const_format::concatcp;
use rust_cgi::{http::Method, http::StatusCode, text_response, Request, Response};
use tracing::warn;

use crate::{
command_listener::CommandResponse,
config::{TeliodDaemonConfig, TeliodDaemonConfigPartial},
ClientCmd, DaemonSocket, TeliodError, TIMEOUT_SEC,
};

const TELIOD_TMP_DIR: &str = "/tmp/nordsecuritymeshnet";
const PID_FILE: &str = concatcp!(TELIOD_TMP_DIR, "/teliod.pid");
const QPKG_DIR: &str = "/share/CACHEDEV1_DATA/.qpkg/NordSecurityMeshnet";
const TELIOD_BIN: &str = concatcp!(QPKG_DIR, "/teliod");
const MESHNET_LOG: &str = concatcp!(QPKG_DIR, "/meshnet.log");
Expand All @@ -27,28 +24,6 @@ const TELIOD_CFG: &str = concatcp!(QPKG_DIR, "/teliod.cfg");
#[cfg(test)]
use tests::TELIOD_CFG;

pub struct PidFile;

impl PidFile {
pub async fn new() -> Result<Self, TeliodError> {
let mut file = OpenOptions::new()
.write(true)
.create(true)
.truncate(true)
.open(PID_FILE)?;
writeln!(file, "{}", process::id())?;
Ok(Self)
}
}

impl Drop for PidFile {
fn drop(&mut self) {
if let Err(e) = std::fs::remove_file(PID_FILE) {
warn!("Failed to remove PID file: {}", e);
}
}
}

macro_rules! teliod_blocking_query {
($command:expr) => {{
let socket_path = DaemonSocket::get_ipc_socket_path();
Expand Down Expand Up @@ -89,20 +64,15 @@ fn is_teliod_running() -> bool {
matches!(teliod_blocking_query!(ClientCmd::GetStatus), Ok(Ok(_)))
}

fn kill_teliod_process() -> Result<(), io::Error> {
match fs::read_to_string(PID_FILE) {
Ok(pid) => {
// result is ignored: trivial/nowhere to log
let _ = Command::new("kill")
.arg("-9")
.arg(pid.trim())
.stdout(std::process::Stdio::null())
.stderr(std::process::Stdio::null())
.status();
fs::remove_file(PID_FILE)
fn shutdown_teliod() -> Result<(), TeliodError> {
if let Ok(Ok(daemon_reply)) = teliod_blocking_query!(ClientCmd::QuitDaemon) {
if CommandResponse::deserialize(&daemon_reply)
.is_ok_and(|response| response == CommandResponse::Ok)
{
return Ok(());
}
Err(e) => Err(e),
}
Err(TeliodError::ClientTimeoutError)
}

fn start_daemon() -> Response {
Expand Down Expand Up @@ -162,20 +132,12 @@ fn start_daemon() -> Response {
}

fn stop_daemon() -> Response {
if is_teliod_running() {
if kill_teliod_process().is_ok() {
text_response(StatusCode::OK, "Application stopped successfully.")
} else {
text_response(
StatusCode::INTERNAL_SERVER_ERROR,
"Failed to stop the application.",
)
}
} else {
match kill_teliod_process() {
Ok(_) => text_response(StatusCode::OK, "Application stopped successfully."),
_ => text_response(StatusCode::GONE, "Application not found."),
}
match shutdown_teliod() {
Ok(_) => text_response(StatusCode::OK, "Application stopped successfully."),
Err(error) => text_response(
StatusCode::INTERNAL_SERVER_ERROR,
format!("Unable to stop application: {error}"),
),
}
}

Expand Down

0 comments on commit 284a1bc

Please sign in to comment.