Skip to main content

consortium_ansible/
lib.rs

1//! # consortium-ansible
2//!
3//! Ansible orchestration with nix-built environments.
4//!
5//! Uses nix to build hermetic ansible environments (pinned version,
6//! collections, roles), copies them to the control node, then runs
7//! playbooks against targets using the DAG executor for parallelism.
8
9pub mod error;
10pub mod inventory;
11pub mod tasks;
12
13pub use error::{AnsibleError, Result};
14
15use consortium::dag::{DagContext, DagReport, ErrorPolicy, StageBuilder};
16use consortium_nix::FleetConfig;
17
18/// Run a playbook against target hosts with a nix-built ansible environment.
19pub fn run_playbook(
20    config: &FleetConfig,
21    targets: &[String],
22    playbook: &str,
23    env_name: &str,
24    check_mode: bool,
25    max_parallel: usize,
26) -> Result<DagReport> {
27    let ansible_config = config
28        .ansible_config
29        .as_ref()
30        .ok_or(AnsibleError::NoConfig)?;
31
32    let ctx = DagContext::new();
33    ctx.set_state("fleet_config", config.clone());
34
35    // Build and copy the ansible env (shared across all hosts)
36    // Then run playbook per host
37    let report = StageBuilder::new()
38        .resources(targets.to_vec())
39        .stage("build-env", Some(1), {
40            let flake_uri = config.flake_uri.clone();
41            let env = env_name.to_string();
42            move |_host| Box::new(tasks::NixBuildAnsibleEnvTask::new(&env, &flake_uri))
43        })
44        .stage("copy-env", Some(1), {
45            let control = ansible_config.control_node.clone();
46            let env = env_name.to_string();
47            move |_host| {
48                Box::new(tasks::NixCopyAnsibleEnvTask {
49                    env_name: env.clone(),
50                    target_host: control.clone(),
51                    target_user: "root".to_string(),
52                })
53            }
54        })
55        .stage("run-playbook", Some(max_parallel), {
56            let pb = playbook.to_string();
57            let env = env_name.to_string();
58            move |host| {
59                Box::new(tasks::AnsiblePlaybookTask::new(host, &pb, &env).with_check(check_mode))
60            }
61        })
62        .error_policy(ErrorPolicy::ContinueIndependent)
63        .context(ctx)
64        .build()
65        .map_err(|e| AnsibleError::Dag(e.to_string()))?
66        .run()
67        .map_err(|e| AnsibleError::Dag(e.to_string()))?;
68
69    Ok(report)
70}