Expand description
§Pupoxide
A high-performance, memory-safe, declarative configuration management tool inspired by Puppet.
Pupoxide leverages the power and safety of Rust and integrates the flexible scripting capabilities of Rhai to allow expressing complex system configurations cleanly, safely, and efficiently.
§Key Features
- Declarative Configuration DSL: Describe files, directories, commands, and packages using a simple Rhai-based DSL.
- Safe Concurrent Execution: Resources are executed in parallel using a Kahn-based topological sort, respecting dependency relationships.
- Resource Mutexes: Package managers (like
aptorbrew) and other conflicting resources are automatically serialized using internal mutex locks. - Hexagonal Architecture: Core domains and applications are decoupled from infrastructure stores via clean ports and adapters.
- Hierarchical Configuration (Stash): Dynamically resolve system variables based on target host facts using a Multi-level Tera templated configuration storage.
- Zero Warnings & High Safety: Built under a strict
#![deny(clippy::unwrap_used)]compiler warning policy.
§Architecture Overview
Pupoxide follows a clean Ports & Adapters (Hexagonal) architectural pattern inside src/:
- Domain (
src/domain/): Houses the primary business entities (likeResource,Catalog,Transaction,Facts, andResourceReport) and abstract port traits (likeResourceProvider). It is highly pure and contains minimal external dependencies. - Application (
src/application/): Defines orchestrations, including DSL registration, manifest evaluation viaPupoxideEngine, and execution graphs viaexecute_transaction. It relies on abstract ports likeStashProviderandStateStore. - Infrastructure (
src/infrastructure/): Implements specific I/O adapters, such as concreteStashfilesystems and transaction logStateStoreadapters. - Interface (
src/interface/): Entry point for CLI configurations, REST handlers, or agent bindings.
§Quick Start Example
The following example demonstrates how to configure the engine, compile a manifest, and apply it to a target system.
§1. Write a Rhai Manifest (site.rhai)
// Declare a package resource
pkg("git", #{
ensure: "present",
});
// Create a custom configuration file depending on git
file("/etc/myapp/config.yaml", #{
ensure: "present",
content: "port: 8080\nenvironment: production",
require: ["package:git"],
});§2. Execute via Rust API
ⓘ
use pupoxide::application::{PupoxideEngine, execute_transaction};
use pupoxide::domain::facts::Facts;
use pupoxide::infrastructure::{Stash, StateStore, FsAdapter};
use std::path::PathBuf;
use std::sync::Arc;
#[tokio::main]
async fn main() -> anyhow::Result<()> {
// 1. Gather host facts
let mut facts = Facts::new();
facts.insert("os_family".to_string(), "Darwin".to_string());
facts.insert("hostname".to_string(), "my-macbook".to_string());
// 2. Initialize Infrastructure Adapters
let env_path = PathBuf::from("./examples/environments/production");
let stash = Stash::new(env_path.clone())?.map(|s| Arc::new(s) as Arc<dyn pupoxide::application::StashProvider>);
let state_store = StateStore::new(env_path.clone());
let provider = Arc::new(FsAdapter::new());
// 3. Build & Run the Pupoxide Engine
let engine = PupoxideEngine::builder()
.with_stash(stash.expect("stash config missing"))
.with_module_path(env_path.join("modules"))
.register_defaults()
.build();
let catalog = engine.run_manifest(
env_path.join("manifests/site.rhai"),
"my-macbook".to_string(),
"production".to_string(),
facts,
)?;
// 4. Apply configuration via Parallel Execution Graph
let reports = execute_transaction(
catalog,
&state_store,
provider,
false, // dry_run
|report| {
println!("Resource [{}]: {:?}", report.resource_id, report.status);
}
).await?;
println!("Successfully synchronized system configuration!");
Ok(())
}