diff --git a/CHANGELOG.md b/CHANGELOG.md index 0876cc1..8d2eec5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,14 @@ All notable changes to this project will be documented in this file. +## [0.1.17] - 2021-12-10 + +### Changed + +- Only create log file before process being really running. +- Fix bug of sysvinit upgrade. +- Use x86_64 as default Windows target. + ## [0.1.16] - 2021-12-09 ### Changed diff --git a/Cargo.lock b/Cargo.lock index 58e2ec3..4c89ebb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2427,7 +2427,7 @@ dependencies = [ [[package]] name = "tat_agent" -version = "0.1.16" +version = "0.1.17" dependencies = [ "async-attributes", "async-std", diff --git a/Cargo.toml b/Cargo.toml index 0498d38..24787c2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "tat_agent" -version = "0.1.16" +version = "0.1.17" edition = "2018" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/install/build.bat b/install/build.bat index 94fef02..cfabd0e 100644 --- a/install/build.bat +++ b/install/build.bat @@ -1,4 +1,4 @@ SET RUSTFLAGS=-C target-feature=+crt-static -rustup target add i686-pc-windows-msvc -cargo build --release --target i686-pc-windows-msvc -copy /Y target\i686-pc-windows-msvc\release\tat_agent.exe install\tat_agent.exe \ No newline at end of file +rustup target add x86_64-pc-windows-msvc +cargo build --release --target x86_64-pc-windows-msvc +copy /Y target\x86_64-pc-windows-msvc\release\tat_agent.exe install\tat_agent.exe \ No newline at end of file diff --git a/install/install.sh b/install/install.sh index a2527af..10b6a7f 100755 --- a/install/install.sh +++ b/install/install.sh @@ -91,10 +91,9 @@ install() { elif has_sysvinit; then cp -f tat_agent_service /etc/init.d/ chmod 755 /etc/init.d/tat_agent_service - # TODO: uncomment following code after 0.1.15 is released. - # if test "${need_restart}" = true; then - /etc/init.d/tat_agent_service restart - # fi + if test "${need_restart}" = true; then + /etc/init.d/tat_agent_service restart + fi which chkconfig > /dev/null 2>&1 if [ $? -eq 0 ]; then echo "use chkconfig to manage service" @@ -110,17 +109,16 @@ install() { fi fi else - # TODO: uncomment following code after 0.1.15 is released. - # if test "${need_restart}" = true; then - echo "no proper daemon manager found, tat_agent can not auto start" - PID=$(cat ${PID_FILE}) - kill ${PID} > /dev/null 2>&1 - sleep 0.1 || sleep 1 - rm -f ${PID_FILE} - cd ${SERVICE_DIR} - ./${TAT_AGENT} - echo "tat_agent started" - # fi + if test "${need_restart}" = true; then + echo "no proper daemon manager found, tat_agent can not auto start" + PID=$(cat ${PID_FILE}) + kill ${PID} > /dev/null 2>&1 + sleep 0.1 || sleep 1 + rm -f ${PID_FILE} + cd ${SERVICE_DIR} + ./${TAT_AGENT} + echo "tat_agent started" + fi fi } diff --git a/install/tat_agent_service b/install/tat_agent_service index 7c6e49f..0d7d723 100644 --- a/install/tat_agent_service +++ b/install/tat_agent_service @@ -43,6 +43,7 @@ stop() { echo "tat_agent not found, nothing to stop" RET=2 fi + rm -f ${PID_FILE} else echo "pid file of tat_agent not exist" RET=3 diff --git a/src/common/consts.rs b/src/common/consts.rs index c5b29ba..e19a004 100644 --- a/src/common/consts.rs +++ b/src/common/consts.rs @@ -31,7 +31,7 @@ cfg_if::cfg_if! { } else if #[cfg(windows)] { pub const TASK_STORE_PATH: &str = "C:\\Program Files\\qcloud\\tat_agent\\tmp\\commands\\"; pub const TASK_LOG_PATH: &str = "C:\\Program Files\\qcloud\\tat_agent\\tmp\\logs\\"; - pub const SELF_UPDATE_PATH: &str = "C:\\Program Files\\qcloud\\tat_agent\\tmp\\self_update"; + pub const SELF_UPDATE_PATH: &str = "C:\\Program Files\\qcloud\\tat_agent\\tmp\\self_update\\"; pub const SELF_UPDATE_SCRIPT: &str = "self_update.bat"; } } diff --git a/src/executor/powershell_command.rs b/src/executor/powershell_command.rs index 71bfd8c..9c99a14 100644 --- a/src/executor/powershell_command.rs +++ b/src/executor/powershell_command.rs @@ -4,13 +4,13 @@ use crate::start_failed_err_info; use async_trait::async_trait; use codepage_strings::Coding; use core::mem; -use log::{debug, error, info}; +use log::{debug, error, info, warn}; use rand::distributions::Alphanumeric; use rand::{thread_rng, Rng}; use std::ffi::OsStr; use std::fmt; use std::fmt::{Debug, Formatter}; -use std::fs::{File, OpenOptions}; +use std::fs::{remove_file, File, OpenOptions}; use std::io::Write; use std::os::windows::ffi::OsStrExt; use std::path::Path; @@ -104,8 +104,6 @@ impl PowerShellCommand { impl MyCommand for PowerShellCommand { /* TODO: 1. support set username - 2. support kill process when cancelled or timout. - 3. support set process group. */ async fn run(&mut self) -> Result<(), String> { info!("=>PowerShellCommand::run()"); @@ -115,15 +113,18 @@ impl MyCommand for PowerShellCommand { // work dir check self.work_dir_check()?; - let log_file = self.open_log_file()?; - // create pipe let (our_pipe, their_pipe) = anon_pipe(true)?; // start child let mut cmd = self.prepare_cmd(their_pipe)?; + let log_file = self.open_log_file()?; let mut child = cmd.spawn().map_err(|e| { *self.base.err_info.lock().unwrap() = e.to_string(); + // remove log_file when process run failed. + if let Err(e) = remove_file(self.base.log_file_path.as_str()) { + warn!("remove log file failed: {:?}", e) + } format!( "PowerShellCommand {}, working_directory:{}, start fail: {}", self.base.cmd_path, self.base.work_dir, e diff --git a/src/executor/proc.rs b/src/executor/proc.rs index 9473263..c7e744d 100644 --- a/src/executor/proc.rs +++ b/src/executor/proc.rs @@ -11,7 +11,7 @@ use crate::common::asserts::GracefulUnwrap; use crate::common::consts::{ FINISH_RESULT_FAILED, FINISH_RESULT_START_FAILED, FINISH_RESULT_SUCCESS, FINISH_RESULT_TERMINATED, FINISH_RESULT_TIMEOUT, METADATA_API, OUTPUT_BYTE_LIMIT_EACH_REPORT, - TASK_LOG_PATH, TASK_STORE_PATH, + TASK_STORE_PATH, }; use crate::cos::ObjectAPI; use crate::cos::COS; @@ -19,9 +19,10 @@ use crate::http::MetadataAPIAdapter; use crate::ontime::timer::Timer; use crate::start_failed_err_info; use async_trait::async_trait; -use log::{debug, error, info}; +use log::{debug, error, info, warn}; use std::fmt; -use std::fs::{File, OpenOptions}; +use std::fs::{create_dir_all, File, OpenOptions}; +use std::path::Path; use std::sync::atomic::Ordering::SeqCst; use std::sync::atomic::{AtomicBool, AtomicU32, AtomicU64, Ordering}; use std::sync::{Arc, Mutex}; @@ -468,17 +469,32 @@ impl BaseCommand { start_failed_err_info!(ERR_SCRIPT_FILE_STORE_FAILED, TASK_STORE_PATH); return Err(ret); } - if self.log_file_path.is_empty() { - let ret = format!("start fail because log file store failed."); - *self.err_info.lock().unwrap() = - start_failed_err_info!(ERR_LOG_FILE_STORE_FAILED, TASK_LOG_PATH); - return Err(ret); - } Ok(()) } fn open_log_file(&self) -> Result { + let parent = Path::new(self.log_file_path.as_str()).parent(); + match parent { + Some(parent) => { + if let Err(e) = create_dir_all(parent) { + return Err(format!( + "fail to open task log file {}: create parent dir fail {}: {:?}", + self.log_file_path, + parent.display(), + e + )); + } + } + None => { + warn!( + "parent dir not found, skip: {}", + self.log_file_path.as_str() + ) + } + } + let res = OpenOptions::new() + .create(true) .write(true) .open(self.log_file_path.clone()); match res { @@ -596,10 +612,10 @@ impl BaseCommand { } #[cfg(test)] mod tests { + use std::fs; use std::fs::File; use std::io::Write; use std::time::{Duration, Instant, SystemTime}; - use std::fs; use log::info; use rand::distributions::Alphanumeric; @@ -683,7 +699,6 @@ mod tests { init_log(); // it doesn't matter even if ./a.sh not exist let log_path = format!("./{}.log", gen_rand_str()); - File::create(log_path.as_str()).unwrap_or_exit("create log path fail."); let ret = new( CMD_PATH, &username(), @@ -700,7 +715,7 @@ mod tests { let ret = cmd.run().await; assert!(ret.is_ok()); info!("cmd running, pid:{}", cmd.pid()); - tokio::time::delay_for(Duration::from_secs(4)).await; + tokio::time::delay_for(Duration::from_secs(10)).await; // now it's NOT a defunct process, cmd will be auto-waited assert!(!is_process_exist(cmd.pid()).await); //thread::sleep(Duration::new(10, 0)); @@ -824,7 +839,6 @@ mod tests { } } let log_path = format!("./{}.log", gen_rand_str()); - File::create(log_path.as_str()).unwrap_or_exit("create log path fail."); let ret = new( filename.as_str(), &username(), @@ -879,7 +893,6 @@ mod tests { } } let log_path = format!("./{}.log", gen_rand_str()); - File::create(log_path.as_str()).unwrap_or_exit("create log path fail."); let ret = new( filename.as_str(), &username(), @@ -965,7 +978,6 @@ mod tests { } } let log_path = format!("./{}.log", gen_rand_str()); - File::create(log_path.as_str()).unwrap_or_exit("create log path fail."); let ret = new( filename.as_str(), &username(), @@ -1020,9 +1032,8 @@ mod tests { .duration_since(SystemTime::UNIX_EPOCH) .unwrap() .as_secs(); - info!("script {} start_time:{}",filename, start_time); + info!("script {} start_time:{}", filename, start_time); let log_path = format!("./{}.log", gen_rand_str()); - File::create(log_path.as_str()).unwrap_or_exit("create log path fail."); let ret = new( filename.as_str(), &username(), @@ -1076,7 +1087,6 @@ mod tests { let filename = format!("./.{}.sh", gen_rand_str()); create_file("echo 'hello world'\nsleep 10 &\ndate", filename.as_str()); let log_path = format!("./{}.log", gen_rand_str()); - File::create(log_path.as_str()).unwrap_or_exit("create log path fail."); let ret = new( filename.as_str(), &username(), @@ -1123,7 +1133,6 @@ mod tests { ); let log_path = format!("./{}.log", gen_rand_str()); - File::create(log_path.as_str()).unwrap_or_exit("create log path fail."); let ret = new( filename.as_str(), &username(), diff --git a/src/executor/shell_command.rs b/src/executor/shell_command.rs index 63a3215..08d5e34 100755 --- a/src/executor/shell_command.rs +++ b/src/executor/shell_command.rs @@ -1,6 +1,6 @@ use std::collections::HashMap; use std::fmt::Debug; -use std::fs::File; +use std::fs::{remove_file, File}; use std::io::Write; use std::path::Path; use std::process::Stdio; @@ -13,7 +13,7 @@ use crate::executor::proc::{BaseCommand, MyCommand}; use crate::start_failed_err_info; use async_trait::async_trait; use libc; -use log::{debug, error, info}; +use log::{debug, error, info, warn}; use procfs::process::Process; use tokio::io::{AsyncReadExt, BufReader}; use tokio::process::{Child, Command}; @@ -147,10 +147,13 @@ impl MyCommand for ShellCommand { let user = self.user_check()?; let log_file = self.open_log_file()?; - // start the process async let mut child = self.prepare_cmd(user).spawn().map_err(|e| { *self.base.err_info.lock().unwrap() = e.to_string(); + // remove log_file when process run failed. + if let Err(e) = remove_file(self.base.log_file_path.as_str()) { + warn!("remove log file failed: {:?}", e) + } format!( "ShellCommand {}, working_directory:{}, start fail: {}", self.base.cmd_path, self.base.work_dir, e diff --git a/src/http/store.rs b/src/http/store.rs index b38d418..2b548a8 100644 --- a/src/http/store.rs +++ b/src/http/store.rs @@ -173,8 +173,6 @@ impl TaskFileStore { return Err("fail to store command in task file".to_string()); } - // create task log file - let _ = self.create_file(&task_log_path, true, false)?; Ok((task_file_path, task_log_path)) } @@ -230,11 +228,10 @@ mod tests { desired_path ); - let (task_file, log_path) = store.store(&task).unwrap(); + let (task_file, _) = store.store(&task).unwrap(); let contents = read_to_string(&task_file).unwrap(); assert_eq!(contents, "ls -l"); store.remove(&task_file); - store.remove(&log_path); let paths = read_dir(Path::new(&task_file).parent().unwrap()).unwrap(); for f in paths { remove_file(f.unwrap().path()).unwrap(); diff --git a/src/http/thread.rs b/src/http/thread.rs index 5e9c528..4edc601 100644 --- a/src/http/thread.rs +++ b/src/http/thread.rs @@ -372,7 +372,7 @@ impl HttpWorker { proc_res .run() .await - .map_err(|e| error!("start process fail {}",e)) + .map_err(|e| error!("start process fail {}", e)) .ok(); let cmd_arc = Arc::new(Mutex::new(proc_res)); @@ -589,7 +589,6 @@ mod tests { .then_return(Ok(ReportTaskFinishResponse {})); let log_path = format!("./{}.log", gen_rand_str()); - File::create(log_path.as_str()).unwrap_or_exit("create log path fail."); let cmd = http_worker .create_proc(filename.as_str(), log_path.as_str(), &task) .await diff --git a/src/ontime/self_update.rs b/src/ontime/self_update.rs index ac08e59..e35e3a4 100644 --- a/src/ontime/self_update.rs +++ b/src/ontime/self_update.rs @@ -272,7 +272,7 @@ fn try_run_agent( unzip_dir: String, agent_filename: String, ) -> Result { - let agent = format!("{}/{}/{}", path, unzip_dir, agent_filename); + let agent = format!("{}{}/{}", path, unzip_dir, agent_filename); let cmd = Command::new(agent).arg("--version").output(); if let Err(e) = cmd { return Err(format!("agent run ret: {:?}", e)); @@ -301,7 +301,7 @@ fn run_self_update_script( unzip_dir: String, script_filename: String, ) -> Result<(), String> { - let script = format!("{}/{}/{}", path, unzip_dir, script_filename); + let script = format!("{}{}/{}", path, unzip_dir, script_filename); #[cfg(unix)] let cmd = Command::new("sh").arg("-c").arg(script).output(); #[cfg(windows)] @@ -326,7 +326,7 @@ fn run_self_update_script( pub fn try_restart_agent() -> Result<(), String> { cfg_if::cfg_if! { if #[cfg(unix)] { - let script = format!("{}/{}/{}", + let script = format!("{}{}/{}", SELF_UPDATE_PATH.to_string(), UPDATE_FILE_UNZIP_DIR.to_string(), INSTALL_SCRIPT.to_string(), diff --git a/src/uname/windows.rs b/src/uname/windows.rs index 5b71cb9..491a0b8 100644 --- a/src/uname/windows.rs +++ b/src/uname/windows.rs @@ -9,7 +9,7 @@ impl Uname { release: String::from("unknown"), version: String::from("unknown"), // TODO: need optimized with real arch. - machine: String::from("i686"), + machine: String::from("x86_64"), }; return Ok(uname); } diff --git a/src/ws/thread.rs b/src/ws/thread.rs index d1f4c0c..c2effbf 100644 --- a/src/ws/thread.rs +++ b/src/ws/thread.rs @@ -70,6 +70,7 @@ pub fn run( .timeout(Duration::from_secs(WS_CONNECT_TIMEOUT)) .map_err(|e| { error!("connect fail:{:?}", e); + thread::sleep(time::Duration::from_secs(WS_RECONNECT_INTERVAL)); panic!(); }) .and_then(|(duplex, _)| {