dora-cli 1.0.0-rc.2

`dora` goal is to be a low latency, composable, and distributed data flow.
use std::path::PathBuf;

use clap::Args;

use crate::command::{Executable, default_tracing};

use super::config::ClusterConfig;
use super::{
    format_daemon_port_arg, format_labels_arg, format_zenoh_peer_arg, print_summary,
    record_ssh_result, run_ssh, ssh_target,
};

/// Install dora-daemon as a systemd service on each machine.
///
/// SSH-es into each machine, writes a systemd unit file, and enables the service.
///
/// Examples:
///
///   dora cluster install cluster.yml
#[derive(Debug, Args)]
#[clap(verbatim_doc_comment)]
pub struct Install {
    /// Path to the cluster configuration file
    #[clap(value_name = "PATH", value_hint = clap::ValueHint::FilePath)]
    config: PathBuf,
}

impl Executable for Install {
    fn execute(self) -> eyre::Result<()> {
        default_tracing()?;
        let config = ClusterConfig::load(&self.config)?;

        let mut failures = Vec::new();

        let zenoh_peer_arg = format_zenoh_peer_arg(config.zenoh_peer.as_deref());
        for machine in &config.machines {
            let target = ssh_target(machine);
            let labels_arg = format_labels_arg(&machine.labels);
            let daemon_port_arg = format_daemon_port_arg(machine.daemon_port);
            let service_name = format!("dora-daemon-{}", machine.id);

            let unit = format!(
                r#"[Unit]
Description=Dora Daemon ({id})
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
ExecStart=dora daemon --machine-id {id} --coordinator-addr {addr} --coordinator-port {port}{daemon_port_arg}{zenoh_peer_arg}{labels} --quiet
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target
"#,
                id = machine.id,
                addr = config.coordinator.addr,
                port = config.coordinator.port,
                labels = labels_arg,
            );

            // Escape single quotes for shell
            let escaped_unit = unit.replace('\'', "'\\''");
            let cmd = format!(
                "echo '{escaped_unit}' | sudo tee /etc/systemd/system/{service_name}.service > /dev/null && sudo systemctl daemon-reload && sudo systemctl enable --now {service_name}"
            );

            println!("Installing {service_name} on {} ({target})", machine.id);
            let result = run_ssh(&target, machine.port, &cmd);
            record_ssh_result(
                &mut failures,
                &machine.id,
                result,
                &format!("{service_name} installed and started"),
            );
        }

        print_summary(
            "daemon(s) installed as systemd services",
            config.machines.len(),
            &failures,
        );

        if failures.is_empty() {
            Ok(())
        } else {
            eyre::bail!(
                "install failed on {}/{} machine(s)",
                failures.len(),
                config.machines.len()
            )
        }
    }
}