소스 검색

Add sysinit function.

ZRY 1 개월 전
부모
커밋
ab1367cd61
8개의 변경된 파일185개의 추가작업 그리고 22개의 파일을 삭제
  1. 1 0
      Cargo.lock
  2. 2 1
      Cargo.toml
  3. 4 0
      src/cfg/etc.rs
  4. 22 2
      src/logger/mod.rs
  5. 13 9
      src/main.rs
  6. 8 0
      src/syscall/error.rs
  7. 52 1
      src/syscall/proc.rs
  8. 83 9
      src/sysinit/mod.rs

+ 1 - 0
Cargo.lock

@@ -1361,6 +1361,7 @@ dependencies = [
  "common_macros",
  "easy-repl",
  "lazy_static",
+ "log",
  "nix 0.26.2",
  "pkg_compile_time",
  "serde",

+ 2 - 1
Cargo.toml

@@ -15,4 +15,5 @@ toml = "0.7.4"
 serde = { version = "1.0", features = ["derive"] }
 common_macros = "0.1.1"
 bcrypt = "0.14.0"
-pkg_compile_time = "0.1.3"
+pkg_compile_time = "0.1.3"
+log = "0.4.17"

+ 4 - 0
src/cfg/etc.rs

@@ -17,6 +17,8 @@ impl EtcConfigDef {
                 sys_loader: "/nagae/elip4ng/bin/chen".to_string(),
                 service_mgr: "/nagae/elip4ng/bin/ran".to_string(),
                 shell_spawner: "/nagae/elip4ng/bin/reimu".to_string(),
+                svc_mgr_exit_restart_limit: 10,
+                svc_mgr_exit_restart_delay_secs: 1,
             },
             env: toml::map::Map::new(),
             boot_default: BootConfigDef::default(),
@@ -41,6 +43,8 @@ pub struct SysCfg {
     pub sys_loader: String,
     pub service_mgr: String,
     pub shell_spawner: String,
+    pub svc_mgr_exit_restart_limit: u64,
+    pub svc_mgr_exit_restart_delay_secs: u64,
 }
 
 #[derive(Deserialize, Clone)]

+ 22 - 2
src/logger/mod.rs

@@ -10,6 +10,10 @@ lazy_static!{
     static ref DEBUG_MODE: AtomicBool = AtomicBool::new(false);
 }
 
+pub trait LoggerWriterSpawner {
+    fn get_writer(&self, prefix: &str) -> LogWriter;
+}
+
 pub struct Logger {
     tx: Sender<String>,
     rx: Receiver<String>,
@@ -39,8 +43,14 @@ impl Logger {
         }
     }
 
-    pub fn get_writer(&mut self, prefix: String) -> LogWriter {
-        LogWriter{tx: self.tx.clone(), prefix }
+    pub fn get_spawner(&self) -> LoggerWriterSpawnerImpl {
+        LoggerWriterSpawnerImpl{tx: self.tx.clone()}
+    }
+}
+
+impl LoggerWriterSpawner for Logger {
+    fn get_writer(&self, prefix: &str) -> LogWriter {
+        LogWriter{tx: self.tx.clone(), prefix: prefix.to_string() }
     }
 }
 
@@ -86,6 +96,16 @@ impl LogWriter {
     }
 }
 
+pub struct LoggerWriterSpawnerImpl{
+    tx: Sender<String>
+}
+
+impl LoggerWriterSpawner for LoggerWriterSpawnerImpl{
+    fn get_writer(&self, prefix: &str) -> LogWriter {
+        LogWriter{tx: self.tx.clone(), prefix: prefix.to_string() }
+    }
+}
+
 enum LogLevel {
     Debug,
     Info,

+ 13 - 9
src/main.rs

@@ -3,6 +3,7 @@ use std::time::Duration;
 use tokio::task::JoinSet;
 use crate::reaper::Reaper;
 use pkg_compile_time::{pkg_compile_date, pkg_compile_time};
+use crate::logger::LoggerWriterSpawner;
 
 mod shell;
 mod syscall;
@@ -37,10 +38,15 @@ async fn main() {
     println!("---- yukari sysinit phase ----");
 
     let mut logmux = logger::Logger::new();
-    let logger_reaper = logmux.get_writer(String::from("zombie_reaper"));
-    let logger_env_load = logmux.get_writer(String::from("env_load"));
-    let logger_sysinit = logmux.get_writer(String::from("sys_init"));
-
+    let logger_reaper = logmux.get_writer("zombie_reaper");
+    let logger_env_load = logmux.get_writer("env_load");
+/*    let logger_sysinit = logmux.get_writer("sys_init_task");
+    let logger_sys_loader_stdout = logmux.get_writer("sys_loader_stdout");
+    let logger_sys_loader_stderr = logmux.get_writer("sys_loader_stderr");
+    let logger_svc_mgr_stdout = logmux.get_writer("svc_mgr_stdout");
+    let logger_svc_mgr_stderr = logmux.get_writer("svc_mgr_stderr");
+*/
+    let logger_spawner_sysinit = logmux.get_spawner();
     let zombie_reaper_res = Reaper::new(logger_reaper);
     let mut zombie_reaper = match zombie_reaper_res {
         Ok(r) => {r}
@@ -49,7 +55,7 @@ async fn main() {
         }
     };
 
-    let mut sys_init = sysinit::SysInit::new(logger_sysinit);
+    let mut sys_init = sysinit::SysInit::new(logger_spawner_sysinit);
 
     let mut task_set = JoinSet::new();
 
@@ -62,16 +68,14 @@ async fn main() {
         let res = sys_init.prepare().await;
         println!("---- yukari sysinit phase end ----");
         match res {
-            None => {
+            Ok(_) => {
                 println!("service management handover to supervisor");
                 println!();
-                println!("< PRESS ENTER > to enter maintenance shell.");
                 sys_init.run().await;
             }
-            Some(err) => {
+            Err(err) => {
                 println!("[Error] error in sysinit phase: {:?}", err);
                 println!();
-                println!("< PRESS ENTER > to enter maintenance shell.");
                 loop{
                     let _ = tokio::time::sleep(Duration::from_secs(10));
                 }

+ 8 - 0
src/syscall/error.rs

@@ -33,6 +33,14 @@ pub struct ExecError {
     err_msg: String
 }
 
+impl ExecError {
+    pub fn from_str(s: &str) -> Self {
+        Self{
+            err_msg: s.to_string()
+        }
+    }
+}
+
 impl Debug for ExecError {
     fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
         write!(f, "{}", self.err_msg)

+ 52 - 1
src/syscall/proc.rs

@@ -1,5 +1,8 @@
 use std::io;
-use std::process::{ExitStatus};
+use std::process::{ExitStatus, Stdio};
+use tokio::io::{AsyncBufReadExt, BufReader};
+use tokio::process::{Command};
+use crate::logger::{LogWriter};
 use crate::syscall::error::ExecError;
 
 fn _exitstatus_convert(res: io::Result<ExitStatus>) -> Result<Option<i32>, ExecError> {
@@ -61,4 +64,52 @@ pub async fn exec_async(program: String) -> Result<Option<i32>, ExecError> {
             Err(ExecError::from(err))
         }
     }
+}
+
+pub async fn exec_async_with_logger(bin: String, stdout_logger: LogWriter, stderr_logger: LogWriter) -> Result<Option<i32>, ExecError> {
+    let mut cmd_run = Command::new(&bin)
+        .stdin(Stdio::null())
+        .stdout(Stdio::piped())
+        .stderr(Stdio::piped())
+        .spawn()?;
+    let cmd_stdout = match cmd_run.stdout.take() {
+        None => {
+            return Err(ExecError::from_str("can not take stdout for child process"))
+        }
+        Some(v) => {v}
+    };
+    let cmd_stderr = match cmd_run.stderr.take(){
+        None => {
+            return Err(ExecError::from_str("can not take stderr for child process"))
+        }
+        Some(v) => {v}
+    };
+    let stdout_reader = BufReader::new(cmd_stdout);
+    let stderr_reader = BufReader::new(cmd_stderr);
+
+    let mut stdout_lines = stdout_reader.lines();
+    let mut stderr_lines = stderr_reader.lines();
+
+    let bin_name_for_stdout_error_msg = bin.clone();
+    tokio::spawn(async move {
+        while let Some(line) = stdout_lines.next_line().await.unwrap_or_else(|e| {
+            eprintln!("error in reading stdout for '{}':{:?}", bin_name_for_stdout_error_msg, e);
+            None
+        }) {
+            stdout_logger.info(line.as_str()).await;
+        }
+    });
+
+    let bin_name_for_stderr_error_msg = bin.clone();
+    tokio::spawn(async move {
+        while let Some(line) = stderr_lines.next_line().await.unwrap_or_else(|e| {
+            eprintln!("error in reading stderr for '{}':{:?}", bin_name_for_stderr_error_msg, e);
+            None
+        }) {
+            stderr_logger.warn(line.as_str()).await;
+        }
+    });
+
+    let run_result = cmd_run.wait().await;
+    _exitstatus_convert(run_result)
 }

+ 83 - 9
src/sysinit/mod.rs

@@ -1,24 +1,98 @@
-use std::io::Error;
+use std::io::{Error, ErrorKind};
 use std::time::Duration;
-use crate::logger::LogWriter;
+use crate::{cfg, syscall};
+use crate::logger::{LoggerWriterSpawner, LoggerWriterSpawnerImpl, LogWriter};
 
 pub struct SysInit {
-    logger: LogWriter,
-    is_ready: bool,
+    logger_spawner: LoggerWriterSpawnerImpl,
+    sysinit_logger: LogWriter,
 }
 
 impl SysInit {
-    pub fn new(logger: LogWriter) ->SysInit {
-        SysInit{logger, is_ready: false}
+    pub fn new(logger_spawner: LoggerWriterSpawnerImpl) ->SysInit {
+        let sysinit_logger = logger_spawner.get_writer("sys_init_task");
+        SysInit{
+            logger_spawner,
+            sysinit_logger,
+        }
     }
 
-    pub async fn prepare(&mut self) -> Option<Error> {
-        None
+    pub async fn prepare(&mut self) -> Result<(), Error> {
+        let loader_bin = cfg::CFG.get().await.get_etc_cfg().sys.sys_loader.clone();
+        let stdout_logger = self.logger_spawner.get_writer("sys_loader_stdout");
+        let stderr_logger = self.logger_spawner.get_writer("sys_loader_stderr");
+        let run_res = syscall::proc::exec_async_with_logger(
+            loader_bin, stdout_logger, stderr_logger,
+        ).await;
+        match run_res {
+            Ok(c) => {
+                match c {
+                    None => {
+                        self.sysinit_logger.info("sys_loader exited with no code.").await;
+                        Ok(())
+                    }
+                    Some(code) => {
+                        if code == 0 {
+                            self.sysinit_logger.info("sys_loader exited with code 0.").await;
+                            std::env::set_var("yukari_sys_loader_exit_code","0");
+                            Ok(())
+                        } else{
+                            self.sysinit_logger.warn(format!("sys_loader exited with non-zero code: {}", code).as_str()).await;
+                            std::env::set_var("yukari_sys_loader_exit_code",format!("{}", code));
+                            Ok(())
+                        }
+                    }
+                }
+            }
+            Err(err) => {
+                Err(std::io::Error::new(ErrorKind::Other, format!("error in run sys_loader: {}", err).as_str()))
+            }
+        }
     }
 
     pub async fn run(&mut self) {
+        let mut restart_limit = cfg::CFG.get().await.get_etc_cfg().sys.svc_mgr_exit_restart_limit;
+        let restart_delay = cfg::CFG.get().await.get_etc_cfg().sys.svc_mgr_exit_restart_delay_secs;
         loop {
-            let _ = tokio::time::sleep(Duration::from_secs(10));
+            let svc_mgr_bin = cfg::CFG.get().await.get_etc_cfg().sys.sys_loader.clone();
+            let stdout_logger = self.logger_spawner.get_writer("svc_mgr_stdout");
+            let stderr_logger = self.logger_spawner.get_writer("svc_mgr_stderr");
+            let run_res = syscall::proc::exec_async_with_logger(
+                svc_mgr_bin, stdout_logger, stderr_logger,
+            ).await;
+            match run_res {
+                Ok(c) => {
+                    match c {
+                        None => {
+                            self.sysinit_logger.warn("svc_mgr exited with no code.").await;
+                        }
+                        Some(code) => {
+                            if code == 0 {
+                                self.sysinit_logger.warn("svc_mgr exited with code 0.").await;
+                            } else {
+                                self.sysinit_logger.warn(format!("svc_mgr exited with non-zero code: {}", code).as_str()).await;
+                            }
+                        }
+                    }
+                }
+                Err(err) => {
+                    self.sysinit_logger.warn(format!("error in run svc_mgr: {}", err).as_str()).await;
+                }
+            };
+            match restart_limit {
+                0 => {
+                    self.sysinit_logger.info("restart svc_mgr, retry counter remains: unlimited").await;
+                }
+                1 => {
+                    self.sysinit_logger.error("svc_mgr restart reach limitation.").await;
+                    return;
+                }
+                _ => {
+                    restart_limit = restart_limit - 1;
+                    self.sysinit_logger.info(format!("restart svc_mgr, retry counter remains: {}", restart_limit).as_str()).await;
+                }
+            }
+            let _ = tokio::time::sleep(Duration::from_secs(restart_delay));
         }
     }
 }