From 20c4bc2c4ceecfb1bd0f81dd0fcd3d2e5e5c934b Mon Sep 17 00:00:00 2001 From: Prabir Shrestha Date: Sun, 22 Dec 2024 22:50:26 -0800 Subject: [PATCH] add support for pre_start and post_start scripts --- README.md | 7 +++++++ src/deploy_file.rs | 8 ++++++++ src/main.rs | 37 +++++++++++++++++++++++++++++++++++++ 3 files changed, 52 insertions(+) diff --git a/README.md b/README.md index ad70ef6..ce74da6 100644 --- a/README.md +++ b/README.md @@ -225,6 +225,10 @@ name = "homepage" runs_on = ["docker1"] # It requires that the traefik stack on docker1 be deployed first depends_on = ["traefik"] +# It has a pre-start script that should be run before the stack is started +pre_start = ["./pre_start"] +# It has a post-script that should be run after the stack is started +post_start = ["./post_start"] ``` The stacks are topologically sorted based on their dependencies and then @@ -232,6 +236,9 @@ started in that order. It is not possible to depend on stacks that are running on other hosts. +`pre_start` and `post_start` scripts can be run to do any necessary setup such +as creating network resources. + ## Stopping and removing a Stack This is a two phase process: diff --git a/src/deploy_file.rs b/src/deploy_file.rs index 0bf7a35..685833d 100644 --- a/src/deploy_file.rs +++ b/src/deploy_file.rs @@ -26,6 +26,14 @@ pub struct StackDeploy { #[serde(default)] pub secret_env: BTreeMap, + /// List of scripts to run before starting the stack + #[serde(default)] + pub pre_start: Vec, + + /// List of scripts to run after starting the stack + #[serde(default)] + pub post_start: Vec, + // TODO: secret_file /// List of host names on which to run this service pub runs_on: Vec, diff --git a/src/main.rs b/src/main.rs index 1ce8b38..fbfb8b2 100644 --- a/src/main.rs +++ b/src/main.rs @@ -155,10 +155,47 @@ fn do_compose_up(db: &KeePassDB, path: &Path, deploy: &StackDeploy) -> anyhow::R "Cannot deploy {path:?} because of the errors above" ); + if !&deploy.pre_start.is_empty() { + let mut cmd = std::process::Command::new(&deploy.pre_start[0]); + cmd.current_dir( + path.parent() + .ok_or_else(|| anyhow::anyhow!("path {path:?} has no parent!?"))?, + ); + for script in &deploy.pre_start[1..] { + cmd.arg(script); + } + for (k, v) in deploy.secret_env.iter() { + db.resolve_value(&v).map(|v| cmd.env(k, v)); + } + let status = cmd + .status() + .with_context(|| format!("failed to run pre_start script in directory of {path:?}"))?; + anyhow::ensure!(status.success(), "pre_script exit status is {status:?}"); + } + let status = cmd .status() .with_context(|| format!("failed to run docker compose up in directory of {path:?}"))?; anyhow::ensure!(status.success(), "exit status is {status:?}"); + + if !&deploy.post_start.is_empty() { + let mut cmd = std::process::Command::new(&deploy.pre_start[0]); + cmd.current_dir( + path.parent() + .ok_or_else(|| anyhow::anyhow!("path {path:?} has no parent!?"))?, + ); + for script in &deploy.post_start[1..] { + cmd.arg(script); + } + for (k, v) in deploy.secret_env.iter() { + db.resolve_value(&v).map(|v| cmd.env(k, v)); + } + let status = cmd + .status() + .with_context(|| format!("failed to run post_start script in directory of {path:?}"))?; + anyhow::ensure!(status.success(), "post_start exit status is {status:?}"); + } + Ok(()) }