Your browser sucks, JavaScript disabled! Gunnar's console needs JavaScript and WebAssembly. Git over SSH on port 2222 does not.

nordisk/Skidbladnir

examples/install-knut-flight.rs

//! N5 — Skidbladnir-driven **system install** of the knut Arrow Flight server.
//!
//! Proves the [`crate::product::ComponentSpec::knut_flight`] spec end-to-end through
//! the REAL installer path (no hand-written unit): stage the pre-built binary into a
//! bundle with the [`skidbladnir::archive::TarZstd`] engine, then hand it to
//! [`skidbladnir::product::SystemdInstaller`], which verifies the bundle, unpacks it
//! under the [`skidbladnir::layout::Layout`], writes the unit + env file, and
//! enables+starts `knut-flight.service` on the system bus.
//!
//! ```sh
//! # 1. build the server binary (in the knut repo):
//! cargo build --release -p knut-flight --bin knut-flight-server
//! # 2. install it as a systemd service (needs root — creates the `_knut` user
//! #    and writes /etc/systemd/system/knut-flight.service):
//! sudo cargo run --example install-knut-flight -- \
//!     ~/git/knut/target/release/knut-flight-server
//! # 3. prove it: `systemctl status knut-flight` + a Flight `list_flights` on :50055.
//! ```
//!
//! Roots default to `/var/lib/lake`, `/var/log/lake`, `/opt/lake` (override with the
//! 2nd/3rd/4th args). Idempotent: re-running just fills any gaps.

use std::path::PathBuf;

use skidbladnir::archive::{Archive, TarZstd};
use skidbladnir::layout::Layout;
use skidbladnir::product::{ComponentSpec, Installer, SystemdInstaller};

fn main() -> anyhow::Result<()> {
    let mut args = std::env::args().skip(1);
    let bin = PathBuf::from(args.next().ok_or_else(|| {
        anyhow::anyhow!(
            "usage: install-knut-flight <knut-flight-server> [data_dir log_dir software_dir]"
        )
    })?);
    anyhow::ensure!(bin.exists(), "binary not found: {}", bin.display());
    let data = args.next().unwrap_or_else(|| "/var/lib/lake".into());
    let log = args.next().unwrap_or_else(|| "/var/log/lake".into());
    let software = args.next().unwrap_or_else(|| "/opt/lake".into());

    let spec = ComponentSpec::knut_flight();

    // 1. Stage the binary at the spec's `bundle_binary` path, then pack a real
    //    TarZstd bundle (content-addressed manifest — the same format install verifies).
    let stage = std::env::temp_dir().join("knut-flight-stage");
    let _ = std::fs::remove_dir_all(&stage);
    let entry = stage.join(&spec.bundle_binary);
    std::fs::create_dir_all(entry.parent().unwrap())?;
    std::fs::copy(&bin, &entry)?;

    let engine = TarZstd::new();
    let bundle = std::env::temp_dir().join("knut-flight.bundle.tar.zst");
    let manifest = engine.pack(&stage, &spec.name, &bundle)?;
    println!(
        "packed bundle {} ({} entries, root_sha256={})",
        bundle.display(),
        manifest.entries.len(),
        &manifest.root_sha256[..16]
    );

    // 2. Install through the REAL SystemdInstaller (verify → unpack → unit → firewall).
    //    trust_root=None ⇒ integrity-only verify (no signing key in this local proof).
    let layout = Layout::dated(&data, &log, &software);
    println!(
        "installing `{}` via SystemdInstaller (system scope)…",
        spec.name
    );
    SystemdInstaller.install(&spec, &layout, &bundle, &engine, None)?;
    println!(
        "installed: unit=knut-flight.service user={} exec={}",
        spec.user,
        spec.installed_binary(&layout).display()
    );
    Ok(())
}