Skip to content
1 change: 1 addition & 0 deletions rust/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

54 changes: 20 additions & 34 deletions rust/agama-autoinstall/src/scripts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,16 +19,15 @@
// find current contact information at www.suse.com.

use std::{
fs::{self, create_dir_all, File},
fs::{self, create_dir_all},
io::Write,
os::unix::fs::OpenOptionsExt,
path::{Path, PathBuf},
process::Output,
};

use agama_lib::http::BaseHTTPClient;
use agama_transfer::Transfer;
use agama_utils::command::run_with_retry;
use agama_utils::command::{create_log_file, run_with_retry};
use anyhow::anyhow;
use url::Url;

Expand Down Expand Up @@ -73,9 +72,18 @@ impl ScriptsRunner {
let path = self.path.join(&file_name);
self.save_script(url, &path).await?;

let command = tokio::process::Command::new(&path);
let stdout_file = create_log_file(&path.with_extension("stdout"))?;
let stderr_file = create_log_file(&path.with_extension("stderr"))?;

let mut command = tokio::process::Command::new(&path);
command.stdout(stdout_file).stderr(stderr_file);
let output = run_with_retry(command).await?;
self.save_logs(&path, output)?;

if let Some(code) = output.status.code() {
let mut file = create_log_file(&path.with_extension("exit"))?;
write!(&mut file, "{}", code)?;
}

Ok(())
}

Expand All @@ -100,7 +108,13 @@ impl ScriptsRunner {
}

async fn save_script(&self, url: &str, path: &PathBuf) -> anyhow::Result<()> {
let mut file = Self::create_file(&path, 0o700)?;
let mut file = fs::OpenOptions::new()
.create(true)
.write(true)
.truncate(true)
.mode(0o700)
.open(&path)?;

while let Err(error) = Transfer::get(url, &mut file, self.insecure) {
eprintln!("Could not load the script from {url}: {error}");
if !self.should_retry(&url, &error.to_string()).await? {
Expand All @@ -111,34 +125,6 @@ impl ScriptsRunner {
Ok(())
}

fn save_logs(&self, path: &Path, output: Output) -> anyhow::Result<()> {
if !output.stdout.is_empty() {
let mut file = Self::create_file(&path.with_extension("stdout"), 0o600)?;
file.write_all(&output.stdout)?;
}

if !output.stderr.is_empty() {
let mut file = Self::create_file(&path.with_extension("stderr"), 0o600)?;
file.write_all(&output.stderr)?;
}

if let Some(code) = output.status.code() {
let mut file = Self::create_file(&path.with_extension("exit"), 0o600)?;
write!(&mut file, "{}", code)?;
}

Ok(())
}

fn create_file(path: &Path, perms: u32) -> std::io::Result<File> {
fs::OpenOptions::new()
.create(true)
.truncate(true)
.write(true)
.mode(perms)
.open(path)
}

async fn should_retry(&self, url: &str, error: &str) -> anyhow::Result<bool> {
let msg = format!(
r#"
Expand Down
1 change: 1 addition & 0 deletions rust/agama-files/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ async-trait = "0.1.89"
tempfile = "3.23.0"
thiserror = "2.0.17"
tokio = { version = "1.48.0", features = ["sync"] }
tracing = "0.1.41"

[dev-dependencies]
tokio-test = "0.4.4"
Expand Down
30 changes: 24 additions & 6 deletions rust/agama-files/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ pub mod service;
pub use service::{Service, Starter};

pub mod message;
mod runner;
pub use runner::ScriptsRunner;

#[cfg(test)]
mod tests {
Expand All @@ -33,6 +35,7 @@ mod tests {
use agama_utils::{
actor::Handler,
api::{
event,
files::{scripts::ScriptsGroup, Config},
Event,
},
Expand All @@ -47,6 +50,7 @@ mod tests {
struct Context {
handler: Handler<Service>,
tmp_dir: TempDir,
events_rx: event::Receiver,
}

impl AsyncTestContext for Context {
Expand All @@ -62,20 +66,28 @@ mod tests {
std::fs::copy("/usr/bin/install", tmp_dir.path().join("usr/bin/install")).unwrap();

// Set up the service
let (events_tx, _events_rx) = broadcast::channel::<Event>(16);
let (events_tx, events_rx) = broadcast::channel::<Event>(16);
let issues = issue::Service::starter(events_tx.clone()).start();
let progress = progress::Service::starter(events_tx.clone()).start();
let questions = question::start(events_tx.clone()).await.unwrap();
let software =
start_software_service(events_tx.clone(), issues, progress.clone(), questions)
.await;
let handler = Service::starter(events_tx.clone(), progress, software)
let software = start_software_service(
events_tx.clone(),
issues,
progress.clone(),
questions.clone(),
)
.await;
let handler = Service::starter(progress, questions, software)
.with_scripts_workdir(tmp_dir.path())
.with_install_dir(tmp_dir.path())
.start()
.await
.unwrap();
Context { handler, tmp_dir }
Context {
handler,
tmp_dir,
events_rx,
}
}
}

Expand Down Expand Up @@ -111,6 +123,12 @@ mod tests {
.await
.unwrap();

// Wait until the scripts are executed.
while let Ok(event) = ctx.events_rx.recv().await {
if matches!(event, Event::ProgressFinished { scope: _ }) {
break;
}
}
// Check that only the pre-script ran
assert!(std::fs::exists(&test_file_1).unwrap());
assert!(!std::fs::exists(&test_file_2).unwrap());
Expand Down
Loading
Loading