gioser

tawasuyu/brahman

Rust 476TOML 190Markdown 50JSON 176602 Definiciones

⎇ 5b9d8107fc41efc09344a70a7f0280ebc64b1e19 crates/apps/matilda/src/main.rs Rust · 106 líneas · 3.7 KB Historia Quién tocó qué crudo

feat(matilda): matilda-apply — puente del plan a la ejecución 5b9d8107f · sergio ·

1//! `matilda` — demostración de administración de servidores.
2//!
3//! Declara un inventario *deseado*, renderiza su `docker-compose.yml` y
4//! su configuración nginx, y luego calcula el *plan* que lleva un
5//! servidor desde un estado actual distinto hasta el deseado.
6//!
7//! Smoke test legible del módulo: `cargo run -p matilda`.
8
9use matilda_core::{Container, Host, Inventory, RestartPolicy, VHost};
10use matilda_config::{compose_file, nginx_sites};
11use matilda_plan::plan;
12
13/// El inventario que queremos tener en el servidor.
14fn desired() -> Inventory {
15    let mut inv = Inventory::new();
16    inv.add_host(Host::new("edge-1", "10.0.0.1").with_tag("prod"));
17
18    inv.add_container(
19        Container::new("web", "nginx:1.27")
20            .with_port(8080, 80)
21            .with_volume("/srv/site", "/usr/share/nginx/html")
22            .with_restart(RestartPolicy::Always),
23    );
24    inv.add_container(
25        Container::new("api", "ghcr.io/jls/api:2.4")
26            .with_port(9000, 9000)
27            .with_env("DATABASE_URL", "postgres://db/app")
28            .with_restart(RestartPolicy::UnlessStopped),
29    );
30    inv.add_container(
31        Container::new("db", "postgres:16")
32            .with_env("POSTGRES_DB", "app")
33            .with_volume("/srv/pgdata", "/var/lib/postgresql/data")
34            .with_restart(RestartPolicy::Always),
35    );
36
37    inv.add_vhost(VHost::to_container("jlsoltech.com", "web", 80).with_alias("www.jlsoltech.com").with_tls());
38    inv.add_vhost(VHost::to_container("api.jlsoltech.com", "api", 9000).with_tls());
39    inv
40}
41
42/// El estado en que está el servidor hoy: `web` con imagen vieja, sin
43/// `api`, y un contenedor `legacy` que ya no se quiere.
44fn current() -> Inventory {
45    let mut inv = Inventory::new();
46    inv.add_host(Host::new("edge-1", "10.0.0.1").with_tag("prod"));
47    inv.add_container(Container::new("web", "nginx:1.25").with_port(8080, 80));
48    inv.add_container(Container::new("db", "postgres:16")
49        .with_env("POSTGRES_DB", "app")
50        .with_volume("/srv/pgdata", "/var/lib/postgresql/data")
51        .with_restart(RestartPolicy::Always));
52    inv.add_container(Container::new("legacy", "old/cgi:1"));
53    inv.add_vhost(VHost::to_container("jlsoltech.com", "web", 80));
54    inv
55}
56
57fn rule(title: &str) {
58    println!("\n── {title} {}", "─".repeat(56usize.saturating_sub(title.len())));
59}
60
61fn main() {
62    let desired = desired();
63
64    rule("docker-compose.yml (deseado)");
65    print!("{}", compose_file(&desired));
66
67    rule("nginx — sites (deseado)");
68    print!("{}", nginx_sites(&desired));
69
70    rule("plan de reconciliación (actual → deseado)");
71    let current = current();
72    let p = plan(&current, &desired);
73    if p.is_empty() {
74        println!("  sin cambios: el servidor ya está al día.");
75    } else {
76        for (i, action) in p.actions.iter().enumerate() {
77            println!("  {:>2}. {}", i + 1, action.describe());
78        }
79        println!(
80            "\n  {} acciones — {} crear, {} actualizar, {} eliminar.",
81            p.len(),
82            p.count(matilda_plan::Op::Create),
83            p.count(matilda_plan::Op::Update),
84            p.count(matilda_plan::Op::Remove),
85        );
86    }
87
88    rule("script de aplicación (lo que correría en el servidor)");
89    let steps = matilda_apply::plan_to_steps(&p, &desired);
90    if steps.is_empty() {
91        println!("  nada que aplicar.");
92    } else {
93        print!("{}", matilda_apply::steps_to_script(&steps));
94    }
95
96    let broken = desired.broken_vhosts();
97    rule("consistencia");
98    if broken.is_empty() {
99        println!("  todos los vhosts apuntan a contenedores existentes. ✔");
100    } else {
101        for v in broken {
102            println!("  ✘ vhost «{}» apunta a un contenedor inexistente", v.domain);
103        }
104    }
105    println!();
106}