Description: A Rust program to collect command outputs across remote hosts in parallel
Authored: 2021-10-20;
Permalink: https://adamflott.com/programming/rust/collect-system-command-output-in-parallel/
categories :
programming;
tags :
parallel;
rust;
In order to generate /systems/, I use a small Rust program to collect the info and format into Markdown for the site.
Only 2 crates are needed, chrono and rayon .
A silly-useful-only-to-me example, but does demonstrate how powerful Rust can
be. The meat lies in the par_iter().for_each()
. This assumes no sharing of
data is required across computations.
use std::{error::Error, io::Write, process::Command};
use rayon::prelude::*;
fn main() {
match run() {
Ok(_) => {}
Err(err) => {
eprintln!("{}", err);
}
}
}
fn sys_and_commands() -> Vec<(&'static str, Vec<Vec<&'static str>>)> {
vec![
(
"host1",
vec![
vec!["cmd1", "arg1"],
],
),
(
"host2",
vec![
vec!["cmd2", "arg2"],
],
),
]
}
fn run() -> Result<(), Box<dyn Error>> {
let cwd = std::env::current_dir()?;
let scs = sys_and_commands();
scs.par_iter().for_each(|sc| {
let mut sys_cwd = cwd.clone();
let ts = chrono::offset::Utc::now();
let ts_str = ts.format("%Y-%m-%d").to_string();
sys_cwd.extend(["..", "..", "content", "systems", sc.0]);
let _ = std::fs::create_dir(sys_cwd.clone());
sys_cwd.extend(["index.md"]);
let mut f = std::fs::File::create(sys_cwd).unwrap();
let hdr = format!(
r#"+++
title = "{}"
description = "{} System Information"
date = {}
[taxonomies]
categories = ["systems"]
+++"#,
sc.0, sc.0, ts_str
);
f.write_all(&hdr.into_bytes()).unwrap();
let now_str = chrono::offset::Utc::now()
.format("\n\ngenerated %Y-%m-%d %H:%M")
.to_string();
f.write_all(&now_str.into_bytes()).unwrap();
for c in &sc.1 {
let mut command = Command::new(c[0]);
for arg in &c[1..] {
command.arg(arg);
}
match command.output() {
Ok(out) => {
let command_str = c.join(" ");
let cmd_hdr = format!("\n## Command '{}'", command_str);
f.write_all(&cmd_hdr.into_bytes()).unwrap();
f.write_all("\n```\n".as_bytes()).unwrap();
f.write_all(&out.stdout).unwrap();
f.write_all("```\n".as_bytes()).unwrap();
f.flush().unwrap();
}
Err(err) => eprintln!("{}", err),
}
}
});
Ok(())
}