From 838132114c85e62d007946936e367fcc20b782a3 Mon Sep 17 00:00:00 2001 From: theMackabu Date: Thu, 4 Jul 2024 01:30:36 -0700 Subject: [PATCH] fix daemon crash + add hcl env import --- Cargo.lock | 88 +++++++++++++++++++++++++++++++++++++++++---- Cargo.toml | 6 ++-- src/cli/import.rs | 82 ++++++++++++++++++++++++++++++++++++++++++ src/cli/internal.rs | 8 +++-- src/cli/mod.rs | 13 ++++--- src/main.rs | 22 ++++++------ src/process/mod.rs | 60 +++++++++++++++++++++---------- test.js | 3 ++ 8 files changed, 235 insertions(+), 47 deletions(-) create mode 100644 src/cli/import.rs create mode 100644 test.js diff --git a/Cargo.lock b/Cargo.lock index e359576..33cca57 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -998,6 +998,45 @@ version = "0.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" +[[package]] +name = "hcl-edit" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46510177a76e68ccd7d75c5af6dfc7d9bf14d5b274211cc35d5abe7f6e72d5b0" +dependencies = [ + "fnv", + "hcl-primitives", + "vecmap-rs", + "winnow 0.6.13", +] + +[[package]] +name = "hcl-primitives" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eaef0959c97781fc9aba104a08e513a14f995b7c12fdcf940d94252d2e4fa884" +dependencies = [ + "itoa", + "kstring", + "ryu", + "serde", + "unicode-ident", +] + +[[package]] +name = "hcl-rs" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba31dbfca0e197057f6d9a070cf87a68d93da5f551d4ad0d44e0f274f7179669" +dependencies = [ + "hcl-edit", + "hcl-primitives", + "indexmap", + "itoa", + "serde", + "vecmap-rs", +] + [[package]] name = "heck" version = "0.4.1" @@ -1176,9 +1215,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.1.0" +version = "2.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f" +checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" dependencies = [ "equivalent", "hashbrown", @@ -1227,9 +1266,9 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.10" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" +checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" [[package]] name = "js-sys" @@ -1240,6 +1279,16 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "kstring" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec3066350882a1cd6d950d055997f379ac37fd39f81cd4d8ed186032eb3c5747" +dependencies = [ + "serde", + "static_assertions", +] + [[package]] name = "lazy_static" version = "1.4.0" @@ -1710,6 +1759,7 @@ dependencies = [ "env_logger", "flate2", "global_placeholders", + "hcl-rs", "home", "include_dir", "inquire", @@ -2273,9 +2323,9 @@ checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4" [[package]] name = "ryu" -version = "1.0.16" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f98d2aa92eebf49b69786be48e4477826b256916e84a57ff2a4f21923b48eb4c" +checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" [[package]] name = "same-file" @@ -2520,6 +2570,12 @@ dependencies = [ "loom", ] +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + [[package]] name = "strsim" version = "0.10.0" @@ -2837,7 +2893,7 @@ dependencies = [ "serde", "serde_spanned", "toml_datetime", - "winnow", + "winnow 0.5.34", ] [[package]] @@ -3167,6 +3223,15 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" +[[package]] +name = "vecmap-rs" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67d9c76f2c769d47dec11c6f4a9cd3be5e5e025a6bce297b07a311a3514ca97d" +dependencies = [ + "serde", +] + [[package]] name = "version_check" version = "0.9.4" @@ -3500,6 +3565,15 @@ dependencies = [ "memchr", ] +[[package]] +name = "winnow" +version = "0.6.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59b5e5f6c299a3c7890b876a2a587f3115162487e704907d9b6cd29473052ba1" +dependencies = [ + "memchr", +] + [[package]] name = "winreg" version = "0.50.0" diff --git a/Cargo.toml b/Cargo.toml index a5f5215..5614e74 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -26,6 +26,8 @@ regex = "1.10.2" libc = "0.2.151" anyhow = "1.0.78" colored = "2.1.0" +inquire = "0.7.5" +hcl-rs = "0.18.0" macros-rs = "0.5.0" termcolor = "1.4.0" once_cell = "1.19.0" @@ -37,6 +39,7 @@ include_dir = "0.7.3" serde_json = "1.0.109" simple-logging = "2.0.2" utoipa-rapidoc = "2.0.0" +update-informer = "1.1.0" pretty_env_logger = "0.5.0" utoipa-swagger-ui = "5.0.0" clap-verbosity-flag = "2.1.2" @@ -50,9 +53,6 @@ chrono = { version = "0.4.31", features = ["serde"] } serde = { version = "1.0.193", features = ["derive"] } nix = { version = "0.27.1", features = ["process", "signal"] } utoipa = { version = "4.1.0", features = ["serde_yaml", "non_strict_integers"] } -update-informer = "1.1.0" -inquire = "0.7.5" - [dependencies.reqwest] version = "0.11.23" diff --git a/src/cli/import.rs b/src/cli/import.rs new file mode 100644 index 0000000..3f8822a --- /dev/null +++ b/src/cli/import.rs @@ -0,0 +1,82 @@ +use colored::Colorize; +use macros_rs::{crashln, string}; +use serde::Deserialize; +use std::{collections::HashMap, fs}; + +use pmc::{ + helpers, + process::{Env, Runner}, +}; + +#[derive(Deserialize, Debug)] +struct ProcessWrapper { + #[serde(alias = "process")] + list: HashMap, +} + +#[derive(Deserialize, Debug)] +struct Process { + script: String, + server: Option, + watch: Option, + #[serde(default)] + env: Env, +} + +#[derive(Deserialize, Debug)] +struct Watch { + path: String, +} + +impl Process { + fn get_watch_path(&self) -> Option { self.watch.as_ref().and_then(|w| Some(w.path.clone())) } +} + +pub fn read_hcl(path: &String) { + let mut servers: Vec = vec![]; + + println!("{} Applying action importProcess", *helpers::SUCCESS); + + let contents = match fs::read_to_string(path) { + Ok(contents) => contents, + Err(err) => crashln!("{} Cannot read file to import.\n{}", *helpers::FAIL, string!(err).white()), + }; + + let hcl_parsed: ProcessWrapper = match hcl::from_str(&contents) { + Ok(hcl) => hcl, + Err(err) => crashln!("{} Cannot parse imported file.\n{}", *helpers::FAIL, string!(err).white()), + }; + + for (name, item) in hcl_parsed.list { + let mut runner = Runner::new(); + let server_name = &item.server.clone().unwrap_or("local".into()); + let (kind, list_name) = super::format(server_name); + + runner = super::Internal { + id: 0, + server_name, + kind: kind.clone(), + runner: runner.clone(), + } + .create(&item.script, &Some(name.clone()), &item.get_watch_path(), true); + + println!("{} Imported {kind}process {name}", *helpers::SUCCESS); + + match runner.find(&name, server_name) { + Some(id) => { + let mut p = runner.get(id); + p.stop(); + p.set_env(item.env); + p.restart(); + } + None => crashln!("{} Failed to write to ({name})", *helpers::FAIL), + } + + if !servers.contains(&list_name) { + servers.push(list_name); + } + } + + servers.iter().for_each(|server| super::Internal::list(&string!("default"), &server)); + println!("{} Applied startProcess to imported items", *helpers::SUCCESS); +} diff --git a/src/cli/internal.rs b/src/cli/internal.rs index d5a871f..c89052a 100644 --- a/src/cli/internal.rs +++ b/src/cli/internal.rs @@ -30,7 +30,7 @@ pub struct Internal<'i> { } impl<'i> Internal<'i> { - pub fn create(mut self, script: &String, name: &Option, watch: &Option) { + pub fn create(mut self, script: &String, name: &Option, watch: &Option, silent: bool) -> Runner { let config = config::read(); let name = match name { Some(name) => string!(name), @@ -61,8 +61,10 @@ impl<'i> Internal<'i> { }; } - println!("{} Creating {}process with ({name})", *helpers::SUCCESS, self.kind); - println!("{} {}Created ({name}) ✓", *helpers::SUCCESS, self.kind); + then!(!silent, println!("{} Creating {}process with ({name})", *helpers::SUCCESS, self.kind)); + then!(!silent, println!("{} {}Created ({name}) ✓", *helpers::SUCCESS, self.kind)); + + return self.runner; } pub fn restart(mut self, name: &Option, watch: &Option, silent: bool) -> Runner { diff --git a/src/cli/mod.rs b/src/cli/mod.rs index ae0c645..a2e792d 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -1,15 +1,16 @@ mod args; pub use args::*; +pub(crate) mod import; pub(crate) mod internal; pub(crate) mod server; use internal::Internal; -use macros_rs::{crashln, string, ternary}; +use macros_rs::{crashln, string, ternary, then}; use pmc::{helpers, process::Runner}; use std::env; -fn format(server_name: &String) -> (String, String) { +pub(crate) fn format(server_name: &String) -> (String, String) { let kind = ternary!(matches!(&**server_name, "internal" | "local"), "", "remote ").to_string(); return (kind, server_name.to_string()); } @@ -24,7 +25,7 @@ pub fn get_version(short: bool) -> String { }; } -pub fn start(name: &Option, args: &Args, watch: &Option, server_name: &String) { +pub fn start(name: &Option, args: &Args, watch: &Option, reset_env: &bool, server_name: &String) { let mut runner = Runner::new(); let (kind, list_name) = format(server_name); @@ -52,13 +53,17 @@ pub fn start(name: &Option, args: &Args, watch: &Option, server_ } else { match args { Args::Id(id) => { + then!(*reset_env, runner.clear_env(*id)); Internal { id: *id, runner, server_name, kind }.restart(name, watch, false); } Args::Script(script) => match runner.find(&script, server_name) { Some(id) => { + then!(*reset_env, runner.clear_env(id)); Internal { id, runner, server_name, kind }.restart(name, watch, false); } - None => Internal { id: 0, runner, server_name, kind }.create(script, name, watch), + None => { + Internal { id: 0, runner, server_name, kind }.create(script, name, watch, false); + } }, } } diff --git a/src/main.rs b/src/main.rs index 7de5302..134d280 100644 --- a/src/main.rs +++ b/src/main.rs @@ -84,6 +84,12 @@ enum Server { // add pmc restore command #[derive(Subcommand)] enum Commands { + /// Import process from environment file + #[command(visible_alias = "add")] + Import { + /// Path of file to import + path: String, + }, /// Start/Restart a process #[command(visible_alias = "restart")] Start { @@ -98,8 +104,10 @@ enum Commands { /// Server #[arg(short, long)] server: Option, + /// Reset environment values + #[arg(short, long)] + reset_env: bool, }, - /// Stop/Kill a process #[command(visible_alias = "kill")] Stop { @@ -109,7 +117,6 @@ enum Commands { #[arg(short, long)] server: Option, }, - /// Stop then remove a process #[command(visible_alias = "rm", visible_alias = "delete")] Remove { @@ -119,7 +126,6 @@ enum Commands { #[arg(short, long)] server: Option, }, - /// Get env of a process #[command(visible_alias = "cmdline")] Env { @@ -129,7 +135,6 @@ enum Commands { #[arg(short, long)] server: Option, }, - /// Get information of a process #[command(visible_alias = "info")] Details { @@ -142,7 +147,6 @@ enum Commands { #[arg(short, long)] server: Option, }, - /// List all processes #[command(visible_alias = "ls")] List { @@ -153,7 +157,6 @@ enum Commands { #[arg(short, long)] server: Option, }, - /// Restore all processes #[command(visible_alias = "resurrect")] Restore { @@ -161,7 +164,6 @@ enum Commands { #[arg(short, long)] server: Option, }, - /// Save all processes to dumpfile #[command(visible_alias = "store")] Save { @@ -169,7 +171,6 @@ enum Commands { #[arg(short, long)] server: Option, }, - /// Get logs from a process Logs { #[clap(value_parser = cli::validate::)] @@ -180,7 +181,6 @@ enum Commands { #[arg(short, long)] server: Option, }, - /// Flush a process log #[command(visible_alias = "clean", visible_alias = "log_rotate")] Flush { @@ -190,7 +190,6 @@ enum Commands { #[arg(short, long)] server: Option, }, - /// Daemon management #[command(visible_alias = "agent", visible_alias = "bgd")] Daemon { @@ -220,7 +219,8 @@ fn main() { env.filter_level(level).init(); match &cli.command { - Commands::Start { name, args, watch, server } => cli::start(name, args, watch, &defaults(server)), + Commands::Import { path } => cli::import::read_hcl(path), + Commands::Start { name, args, watch, server, reset_env } => cli::start(name, args, watch, reset_env, &defaults(server)), Commands::Stop { item, server } => cli::stop(item, &defaults(server)), Commands::Remove { item, server } => cli::remove(item, &defaults(server)), Commands::Restore { server } => Internal::restore(&defaults(server)), diff --git a/src/process/mod.rs b/src/process/mod.rs index cc9dc5d..64e1fa4 100644 --- a/src/process/mod.rs +++ b/src/process/mod.rs @@ -105,7 +105,7 @@ pub struct ProcessWrapper { pub runner: Arc>, } -type Env = BTreeMap; +pub type Env = BTreeMap; #[derive(Clone, Debug, Deserialize, Serialize)] pub struct Process { @@ -286,27 +286,33 @@ impl Runner { stop(process.pid); if let Err(err) = std::env::set_current_dir(&path) { - crashln!("{} Failed to set working directory {:?}\nError: {:#?}", *helpers::FAIL, path, err); - }; + process.running = false; + process.children = vec![]; + process.crash.crashed = true; + println!("{} Failed to set working directory {:?}\nError: {:#?}", *helpers::FAIL, path, err); + } else { + let mut temp_env = process.env.iter().map(|(key, value)| format!("{}={}", key, value)).collect::>(); + temp_env.extend(unix::env()); - process.pid = run(ProcessMetadata { - args: config.args, - name: name.clone(), - shell: config.shell, - log_path: config.log_path, - command: script.to_string(), - env: unix::env(), - }); + process.pid = run(ProcessMetadata { + args: config.args, + name: name.clone(), + shell: config.shell, + log_path: config.log_path, + command: script.to_string(), + env: temp_env, + }); - process.running = true; - process.children = vec![]; - process.started = Utc::now(); - process.crash.crashed = false; - process.env = env::vars().collect(); + process.running = true; + process.children = vec![]; + process.started = Utc::now(); + process.crash.crashed = false; + process.env.extend(env::vars().collect::()); - then!(dead, process.restarts += 1); - then!(dead, process.crash.value += 1); - then!(!dead, process.crash.value = 0); + then!(dead, process.restarts += 1); + then!(dead, process.crash.value += 1); + then!(!dead, process.crash.value = 0); + } } return self; @@ -369,6 +375,16 @@ impl Runner { return self; } + pub fn set_env(&mut self, id: usize, env: Env) -> &mut Self { + self.process(id).env.extend(env); + return self; + } + + pub fn clear_env(&mut self, id: usize) -> &mut Self { + self.process(id).env = BTreeMap::new(); + return self; + } + pub fn set_children(&mut self, id: usize, children: Vec) -> &mut Self { self.process(id).children = children; return self; @@ -557,6 +573,12 @@ impl ProcessWrapper { /// Get the borrowed runner reference (lives till program end) pub fn get_runner(&mut self) -> &Runner { Box::leak(Box::new(lock!(self.runner))) } + /// Append new environment values to the process item + pub fn set_env(&mut self, env: Env) { lock!(self.runner).set_env(self.id, env).save(); } + + /// Clear environment values of the process item + pub fn clear_env(&mut self) { lock!(self.runner).clear_env(self.id).save(); } + /// Get a json dump of the process item pub fn fetch(&self) -> ItemSingle { let mut runner = lock!(self.runner); diff --git a/test.js b/test.js new file mode 100644 index 0000000..63ab4dd --- /dev/null +++ b/test.js @@ -0,0 +1,3 @@ +(function wait() { + setTimeout(wait, 1000); +})(); -- GitLab