From dd51dcd3029a941af17d80ef97829e5585bb0960 Mon Sep 17 00:00:00 2001 From: Jean-Gabriel Gill-Couture Date: Wed, 11 Jun 2025 15:14:20 -0400 Subject: [PATCH] docs: Chose README version and move around documentation bits to their relevant places --- README.md | 149 ++++++++++++++++++++------------------ README_v2.md | 141 ------------------------------------ docs/README.md | 1 + docs/cyborg-metaphor.md | 13 ++++ harmony_cli/README.md | 27 +++++++ opnsense-config/README.md | 146 +++++++++++++++++++++++++++++++++++++ 6 files changed, 264 insertions(+), 213 deletions(-) delete mode 100644 README_v2.md create mode 100644 docs/README.md create mode 100644 docs/cyborg-metaphor.md create mode 100644 harmony_cli/README.md create mode 100644 opnsense-config/README.md diff --git a/README.md b/README.md index e2cb489..4ebf712 100644 --- a/README.md +++ b/README.md @@ -1,37 +1,31 @@ # Harmony -### Open Infrastructure Orchestration for Enterprise +[![Build](https://git.nationtech.io/NationTech/harmony/actions/workflows/check.yml/badge.svg)](https://git.nationtech.io/nationtech/harmony) +[![License](https://img.shields.io/badge/license-AGPLv3-blue?style=flat-square)](LICENSE) -Harmony is an open-source orchestrator designed to **unify** the **entire software lifecycle** within a **single, coherent codebase**. It seamlessly **integrates project creation, infrastructure provisioning, and application deployment** across all your environments—**from a local mini-cluster to a full-scale production setup.** +**Open-source infrastructure orchestration that treats your platform like first-class code.** -Built on the principles of **Infrastructure as Code (IaC)** and **Platform Engineering**, Harmony leverages the **full power** of a real programming language **(Rust)** to provide a robust, type-safe, and unified developer experience. +Harmony unifies project scaffolding, infrastructure provisioning, application deployment, and day-2 operations in **one strongly-typed Rust codebase**. From a developer laptop to a global production cluster, a single source of truth drives the full software lifecycle. -## The Harmony Philosophy +--- -Infrastructure is a requirement for nearly all software, but it isn't your core business. It's ours. Harmony provides an expert-designed foundation for your applications, allowing you to focus on the features that matter to your customers. +## 1 · The Harmony Philosophy -### Principle 1: Infrastructure as Resilient Code, Not Fragile Configuration. +Infrastructure is essential, but it shouldn’t be your core business. Harmony is built on three guiding principles that make modern platforms reliable, repeatable, and easy to reason about. -- The Problem: Traditional infrastructure is managed with static files (like YAML) and brittle scripts. These are error-prone, hard to test, and don't scale with complexity. -- The Harmony Way: We treat infrastructure with the same seriousness as application code. By using a powerful, type-safe programming language (Rust), we define infrastructure as living code that can be tested, reused, and reasoned about, making it fundamentally more robust. +| Principle | What it means for you | +|-----------|-----------------------| +| **Infrastructure as Resilient Code** | Replace sprawling YAML and bash scripts with type-safe Rust. Test, refactor, and version your platform just like application code. | +| **Prove It Works — Before You Deploy** | Harmony uses the compiler to verify that your application’s needs match the target environment’s capabilities at **compile-time**, eliminating an entire class of runtime outages. | +| **One Unified Model** | Software and infrastructure are a single system. Harmony models them together, enabling deep automation—from bare-metal servers to Kubernetes workloads—with zero context switching. | -### Principle 2: From "Hope It Works" to "Prove It Works". +These principles surface as simple, ergonomic Rust APIs that let teams focus on their product while trusting the platform underneath. -- The Problem: With conventional tools, you only discover if a deployment plan is valid when you run it—often in a staging or production environment. -- The Harmony Way: We believe correctness should be a guarantee, not a hope. Harmony uses the compiler to prove that your application's needs are compatible with your infrastructure's capabilities before deployment. This eliminates entire classes of configuration errors at the earliest possible stage. +--- -### Principle 3: A Unified Model for a Unified Reality. +## 2 · Quick Start -- The Problem: In reality, software and infrastructure are a single, interdependent system. Yet, we manage them with separate, disjointed tools, creating a gap where errors and inconsistencies thrive. -- The Harmony Way: We model the system as it truly is: a single entity. Harmony creates a unified codebase where application and infrastructure logic live together, enabling deep integration and holistic management of your entire platform, from bare-metal hardware to the final application. - -If you like metaphors, see this one : [cyborg-metaphor](docs/cyborg-metaphor.md) - -## Quick Start: Deploying a Full LAMP Stack - -The following example demonstrates how to define and deploy a complete, production-grade LAMP stack. Harmony will handle everything: setting up a local Kubernetes cluster, building a containerized PHP application, deploying a MariaDB database, and configuring monitoring. - -#### `main.rs` +The snippet below spins up a complete **production-grade LAMP stack** with monitoring. Swap it for your own scores to deploy anything from microservices to machine-learning pipelines. ```rust use harmony::{ @@ -47,20 +41,11 @@ use harmony::{ #[tokio::main] async fn main() { - // This here is the whole configuration to: - // - Setup a local K3D cluster (if not already running) - // - Build a docker image with the PHP project and production-grade settings - // - Deploy a MariaDB database using a production-grade Helm chart - // - Deploy the new container using a Kubernetes Deployment - // - Configure networking between the PHP container and the database - // - Provision a public route and an SSL certificate automatically on production environments - // - // Enjoy :) + // 1. Describe what you want let lamp_stack = LAMPScore { - name: "harmony-lamp-demo".to_string(), - domain: Url::Url(url::Url::parse("https://lampdemo.harmony.nationtech.io").unwrap()), - php_version: Version::from("8.4.4").unwrap(), - // This config can be extended as needed for more complicated configurations + name: "harmony-lamp-demo".into(), + domain: Url::Url(url::Url::parse("https://lampdemo.example.com").unwrap()), + php_version: Version::from("8.3.0").unwrap(), config: LAMPConfig { project_root: "./php".into(), database_size: "4Gi".into(), @@ -68,69 +53,89 @@ async fn main() { }, }; - // You can choose the type of Topology you want. We suggest starting with the - // K8sAnywhereTopology, as it is the most automatic one. It enables you to easily deploy - // locally, to a development environment from a CI, to staging, and to production - // with settings that automatically adapt to each environment grade. + // 2. Pick where it should run let mut maestro = Maestro::::initialize( - Inventory::autoload(), - K8sAnywhereTopology::from_env(), + Inventory::autoload(), // auto-detect hardware / kube-config + K8sAnywhereTopology::from_env(), // local k3d, CI, staging, prod… ) .await .unwrap(); - // Attach additional features like a full monitoring and alerting stack - let mut monitoring_stack_score = MonitoringAlertingStackScore::new(); - monitoring_stack_score.namespace = Some(lamp_stack.config.namespace.clone()); + // 3. Enhance with extra scores (monitoring, CI/CD, …) + let mut monitoring = MonitoringAlertingStackScore::new(); + monitoring.namespace = Some(lamp_stack.config.namespace.clone()); - maestro.register_all(vec![Box::new(lamp_stack), Box::new(monitoring_stack_score)]); + maestro.register_all(vec![Box::new(lamp_stack), Box::new(monitoring)]); - // Here we bootstrap the CLI, which provides useful interactive features. + // 4. Launch an interactive CLI / TUI harmony_cli::init(maestro, None).await.unwrap(); } - -// That's it. The end of your Infrastructure as Code. ``` -### Running the Example - -To launch the orchestrator, simply run the project: +Run it: ```bash cargo run ``` -This will start Harmony, which will analyze the code, determine the required state, and apply the necessary changes to match your definition. It will present you with an interactive TUI to review and approve the execution plan. +Harmony analyses the code, shows an execution plan in a TUI, and applies it once you confirm. Same code, same binary—every environment. -## Core Concepts +--- -Harmony is built around a few key architectural concepts: +## 3 · Core Concepts -- **Scores**: A `Score` is a declarative, high-level definition of a resource or application you want to exist (e.g., `LAMPScore`, `PostgresClusterScore`). It defines *what* you want, not *how* to achieve it. -- **Interprets**: An `Interpret` contains the imperative logic that brings a `Score` to life. It's the "how" that translates the declarative goal into concrete actions, like running `kubectl` commands or calling a cloud provider API. -- **Topology**: A `Topology` defines *where* your infrastructure runs. It's an abstraction over your target environment, whether it's a local `k3d` cluster, a bare-metal server, or a public cloud provider. `K8sAnywhereTopology` is a powerful default that adapts to any Kubernetes environment. -- **Maestro**: The `Maestro` is the central orchestrator. It loads the inventory, initializes the `Topology`, and executes the `Interprets` for all registered `Scores`. +| Term | One-liner | +|------|-----------| +| **Score** | Declarative description of the desired state (e.g., `LAMPScore`). | +| **Interpret** | Imperative logic that realises a `Score` on a specific environment. | +| **Topology** | An environment (local k3d, AWS, bare-metal) exposing verified *Capabilities* (Kubernetes, DNS, …). | +| **Maestro** | Orchestrator that compiles Scores + Topology, ensuring all capabilities line up **at compile-time**. | +| **Inventory** | Optional catalogue of physical assets for bare-metal and edge deployments. | -![Harmony Core Architecture](docs/diagrams/Harmony_Core_Architecture.drawio.svg) +A visual overview is in the diagram below. -## Contributing & Deeper Dive +[Harmony Core Architecture](docs/diagrams/Harmony_Core_Architecture.drawio.svg) -Contributions are welcome! Whether it's improving the core, adding a new `Score`, or enhancing the documentation, we'd love to have your help. +--- -For a deeper understanding of our design decisions, please see our **Architectural Decision Records (ADRs)**: +## 4 · Install -- [ADR-001: Rust as the Primary Language] -- [ADR-003: Infrastructure Abstractions] -- [ADR-006: Secret Management] -- [ADR-011: Multi Tenant Cluster] -- ... and more in the `/adr` directory. +Prerequisites: -Detailed technical guides, such as **how to extend Harmony to support new hardware (e.g., OPNsense)**, can be found in the `/docs` section of this repository. +* Rust +* Docker (if you deploy locally) +* `kubectl` / `helm` for Kubernetes-based topologies -## License +```bash +git clone https://git.nationtech.io/nationtech/harmony +cd harmony +cargo build --release # builds the CLI, TUI and libraries +``` -This project is licensed under the AGLP License. See the [LICENSE](LICENSE) file for details. +--- -Why AGPL ? Because we believe a strong copyleft license is what enables and empowers all use cases founded in good will, aiming at bringing forward our world towards a better place by leveraging humanity's greatest strenght : collaboration. +## 5 · Learning More -We are totally fine with companies forking harmony and beating us at our own game of creating the best infrastructure orchestration tool. But this has been built for the community and must stay open, so we're forcing copyleft terms upon this project to make sure they are not allowed to keep it just for them. +* **Architectural Decision Records** – dive into the rationale + - [ADR-001 · Why Rust](adr/001-rust.md) + - [ADR-003 · Infrastructure Abstractions](adr/003-infrastructure-abstractions.md) + - [ADR-006 · Secret Management](adr/006-secret-management.md) + - [ADR-011 · Multi-Tenant Cluster](adr/011-multi-tenant-cluster.md) + +* **Extending Harmony** – write new Scores / Interprets, add hardware like OPNsense firewalls, or embed Harmony in your own tooling (`/docs`). + +* **Community** – discussions and roadmap live in [GitLab issues](https://git.nationtech.io/nationtech/harmony/-/issues). PRs, ideas, and feedback are welcome! + +--- + +## 6 · License + +Harmony is released under the **GNU AGPL v3**. + +> We choose a strong copyleft license to ensure the project—and every improvement to it—remains open and benefits the entire community. Fork it, enhance it, even out-innovate us; just keep it open. + +See [LICENSE](LICENSE) for the full text. + +--- + +*Made with ❤️ & 🦀 by the NationTech and the Harmony community* diff --git a/README_v2.md b/README_v2.md deleted file mode 100644 index 4ebf712..0000000 --- a/README_v2.md +++ /dev/null @@ -1,141 +0,0 @@ -# Harmony - -[![Build](https://git.nationtech.io/NationTech/harmony/actions/workflows/check.yml/badge.svg)](https://git.nationtech.io/nationtech/harmony) -[![License](https://img.shields.io/badge/license-AGPLv3-blue?style=flat-square)](LICENSE) - -**Open-source infrastructure orchestration that treats your platform like first-class code.** - -Harmony unifies project scaffolding, infrastructure provisioning, application deployment, and day-2 operations in **one strongly-typed Rust codebase**. From a developer laptop to a global production cluster, a single source of truth drives the full software lifecycle. - ---- - -## 1 · The Harmony Philosophy - -Infrastructure is essential, but it shouldn’t be your core business. Harmony is built on three guiding principles that make modern platforms reliable, repeatable, and easy to reason about. - -| Principle | What it means for you | -|-----------|-----------------------| -| **Infrastructure as Resilient Code** | Replace sprawling YAML and bash scripts with type-safe Rust. Test, refactor, and version your platform just like application code. | -| **Prove It Works — Before You Deploy** | Harmony uses the compiler to verify that your application’s needs match the target environment’s capabilities at **compile-time**, eliminating an entire class of runtime outages. | -| **One Unified Model** | Software and infrastructure are a single system. Harmony models them together, enabling deep automation—from bare-metal servers to Kubernetes workloads—with zero context switching. | - -These principles surface as simple, ergonomic Rust APIs that let teams focus on their product while trusting the platform underneath. - ---- - -## 2 · Quick Start - -The snippet below spins up a complete **production-grade LAMP stack** with monitoring. Swap it for your own scores to deploy anything from microservices to machine-learning pipelines. - -```rust -use harmony::{ - data::Version, - inventory::Inventory, - maestro::Maestro, - modules::{ - lamp::{LAMPConfig, LAMPScore}, - monitoring::monitoring_alerting::MonitoringAlertingStackScore, - }, - topology::{K8sAnywhereTopology, Url}, -}; - -#[tokio::main] -async fn main() { - // 1. Describe what you want - let lamp_stack = LAMPScore { - name: "harmony-lamp-demo".into(), - domain: Url::Url(url::Url::parse("https://lampdemo.example.com").unwrap()), - php_version: Version::from("8.3.0").unwrap(), - config: LAMPConfig { - project_root: "./php".into(), - database_size: "4Gi".into(), - ..Default::default() - }, - }; - - // 2. Pick where it should run - let mut maestro = Maestro::::initialize( - Inventory::autoload(), // auto-detect hardware / kube-config - K8sAnywhereTopology::from_env(), // local k3d, CI, staging, prod… - ) - .await - .unwrap(); - - // 3. Enhance with extra scores (monitoring, CI/CD, …) - let mut monitoring = MonitoringAlertingStackScore::new(); - monitoring.namespace = Some(lamp_stack.config.namespace.clone()); - - maestro.register_all(vec![Box::new(lamp_stack), Box::new(monitoring)]); - - // 4. Launch an interactive CLI / TUI - harmony_cli::init(maestro, None).await.unwrap(); -} -``` - -Run it: - -```bash -cargo run -``` - -Harmony analyses the code, shows an execution plan in a TUI, and applies it once you confirm. Same code, same binary—every environment. - ---- - -## 3 · Core Concepts - -| Term | One-liner | -|------|-----------| -| **Score** | Declarative description of the desired state (e.g., `LAMPScore`). | -| **Interpret** | Imperative logic that realises a `Score` on a specific environment. | -| **Topology** | An environment (local k3d, AWS, bare-metal) exposing verified *Capabilities* (Kubernetes, DNS, …). | -| **Maestro** | Orchestrator that compiles Scores + Topology, ensuring all capabilities line up **at compile-time**. | -| **Inventory** | Optional catalogue of physical assets for bare-metal and edge deployments. | - -A visual overview is in the diagram below. - -[Harmony Core Architecture](docs/diagrams/Harmony_Core_Architecture.drawio.svg) - ---- - -## 4 · Install - -Prerequisites: - -* Rust -* Docker (if you deploy locally) -* `kubectl` / `helm` for Kubernetes-based topologies - -```bash -git clone https://git.nationtech.io/nationtech/harmony -cd harmony -cargo build --release # builds the CLI, TUI and libraries -``` - ---- - -## 5 · Learning More - -* **Architectural Decision Records** – dive into the rationale - - [ADR-001 · Why Rust](adr/001-rust.md) - - [ADR-003 · Infrastructure Abstractions](adr/003-infrastructure-abstractions.md) - - [ADR-006 · Secret Management](adr/006-secret-management.md) - - [ADR-011 · Multi-Tenant Cluster](adr/011-multi-tenant-cluster.md) - -* **Extending Harmony** – write new Scores / Interprets, add hardware like OPNsense firewalls, or embed Harmony in your own tooling (`/docs`). - -* **Community** – discussions and roadmap live in [GitLab issues](https://git.nationtech.io/nationtech/harmony/-/issues). PRs, ideas, and feedback are welcome! - ---- - -## 6 · License - -Harmony is released under the **GNU AGPL v3**. - -> We choose a strong copyleft license to ensure the project—and every improvement to it—remains open and benefits the entire community. Fork it, enhance it, even out-innovate us; just keep it open. - -See [LICENSE](LICENSE) for the full text. - ---- - -*Made with ❤️ & 🦀 by the NationTech and the Harmony community* diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 0000000..a125fce --- /dev/null +++ b/docs/README.md @@ -0,0 +1 @@ +Not much here yet, see the `adr` folder for now. More to come in time! diff --git a/docs/cyborg-metaphor.md b/docs/cyborg-metaphor.md new file mode 100644 index 0000000..d74536e --- /dev/null +++ b/docs/cyborg-metaphor.md @@ -0,0 +1,13 @@ +## Conceptual metaphor : The Cyborg and the Central Nervous System + +At the heart of Harmony lies a core belief: in modern, decentralized systems, **software and infrastructure are not separate entities.** They are a single, symbiotic organism—a cyborg. + +The software is the electronics, the "mind"; the infrastructure is the biological host, the "body". They live or die, thrive or sink together. + +Traditional approaches attempt to manage this complex organism with fragmented tools: static YAML for configuration, brittle scripts for automation, and separate Infrastructure as Code (IaC) for provisioning. This creates a disjointed system that struggles to scale or heal itself, making it inadequate for the demands of fully automated, enterprise-grade clusters. + +Harmony's goal is to provide the **central nervous system for this cyborg**. We aim to achieve the full automation of complex, decentralized clouds by managing this integrated entity holistically. + +To achieve this, a tool must be both robust and powerful. It must manage the entire lifecycle—deployment, upgrades, failure recovery, and decommissioning—with precision. This requires full control over application packaging and a deep, intrinsic integration between the software and the infrastructure it inhabits. + +This is why Harmony uses a powerful, living language like Rust. It replaces static, lifeless configuration files with a dynamic, breathing codebase. It allows us to express the complex relationships and behaviors of a modern distributed system, enabling the creation of truly automated, resilient, and powerful platforms that can thrive. diff --git a/harmony_cli/README.md b/harmony_cli/README.md new file mode 100644 index 0000000..370a14a --- /dev/null +++ b/harmony_cli/README.md @@ -0,0 +1,27 @@ +## Quick demo + +`cargo run -p example-tui` + +This will launch Harmony's minimalist terminal ui which embeds a few demo scores. + +Usage instructions will be displayed at the bottom of the TUI. + +`cargo run --bin example-cli -- --help` + +This is the harmony CLI, a minimal implementation + +The current help text: + +``` +Usage: example-cli [OPTIONS] + +Options: + -y, --yes Run score(s) or not + -f, --filter Filter query + -i, --interactive Run interactive TUI or not + -a, --all Run all or nth, defaults to all + -n, --number Run nth matching, zero indexed [default: 0] + -l, --list list scores, will also be affected by run filter + -h, --help Print help + -V, --version Print version``` + diff --git a/opnsense-config/README.md b/opnsense-config/README.md new file mode 100644 index 0000000..c31dc23 --- /dev/null +++ b/opnsense-config/README.md @@ -0,0 +1,146 @@ +## Supporting a new field in OPNSense `config.xml` + +Two steps: +- Supporting the field in `opnsense-config-xml` +- Enabling Harmony to control the field + +We'll use the `filename` field in the `dhcpcd` section of the file as an example. + +### Supporting the field + +As type checking if enforced, every field from `config.xml` must be known by the code. Each subsection of `config.xml` has its `.rs` file. For the `dhcpcd` section, we'll modify `opnsense-config-xml/src/data/dhcpd.rs`. + +When a new field appears in the xml file, an error like this will be thrown and Harmony will panic : +``` + Running `/home/stremblay/nt/dir/harmony/target/debug/example-nanodc` +Found unauthorized element filename +thread 'main' panicked at opnsense-config-xml/src/data/opnsense.rs:54:14: +OPNSense received invalid string, should be full XML: () + +``` + +Define the missing field (`filename`) in the `DhcpInterface` struct of `opnsense-config-xml/src/data/dhcpd.rs`: + +```rust +pub struct DhcpInterface { + ... + pub filename: Option, +``` + +Harmony should now be fixed, build and run. + +### Controlling the field + +Define the `xml field setter` in `opnsense-config/src/modules/dhcpd.rs`. + +```rust +impl<'a> DhcpConfig<'a> { + ... + pub fn set_filename(&mut self, filename: &str) { + self.enable_netboot(); + self.get_lan_dhcpd().filename = Some(filename.to_string()); + } + ... +``` + +Define the `value setter` in the `DhcpServer trait` in `domain/topology/network.rs` + +```rust +#[async_trait] +pub trait DhcpServer: Send + Sync { + ... + async fn set_filename(&self, filename: &str) -> Result<(), ExecutorError>; + ... +``` + +Implement the `value setter` in each `DhcpServer` implementation. +`infra/opnsense/dhcp.rs`: + +```rust +#[async_trait] +impl DhcpServer for OPNSenseFirewall { + ... + async fn set_filename(&self, filename: &str) -> Result<(), ExecutorError> { + { + let mut writable_opnsense = self.opnsense_config.write().await; + writable_opnsense.dhcp().set_filename(filename); + debug!("OPNsense dhcp server set filename {filename}"); + } + + Ok(()) + } + ... +``` + +`domain/topology/ha_cluster.rs` +```rust +#[async_trait] +impl DhcpServer for DummyInfra { + ... + async fn set_filename(&self, _filename: &str) -> Result<(), ExecutorError> { + unimplemented!("{}", UNIMPLEMENTED_DUMMY_INFRA) + } + ... +``` + +Add the new field to the DhcpScore in `modules/dhcp.rs` + +```rust +pub struct DhcpScore { + ... + pub filename: Option, +``` + +Define it in its implementation in `modules/okd/dhcp.rs` + +```rust +impl OKDDhcpScore { + ... + Self { + dhcp_score: DhcpScore { + ... + filename: Some("undionly.kpxe".to_string()), +``` + +Define it in its implementation in `modules/okd/bootstrap_dhcp.rs` + +```rust +impl OKDDhcpScore { + ... + Self { + dhcp_score: DhcpScore::new( + ... + Some("undionly.kpxe".to_string()), +``` + +Update the interpret (function called by the `execute` fn of the interpret) so it now updates the `filename` field value in `modules/dhcp.rs` + +```rust +impl DhcpInterpret { + ... + let filename_outcome = match &self.score.filename { + Some(filename) => { + let dhcp_server = Arc::new(topology.dhcp_server.clone()); + dhcp_server.set_filename(&filename).await?; + Outcome::new( + InterpretStatus::SUCCESS, + format!("Dhcp Interpret Set filename to {filename}"), + ) + } + None => Outcome::noop(), + }; + + if next_server_outcome.status == InterpretStatus::NOOP + && boot_filename_outcome.status == InterpretStatus::NOOP + && filename_outcome.status == InterpretStatus::NOOP + + ... + + Ok(Outcome::new( + InterpretStatus::SUCCESS, + format!( + "Dhcp Interpret Set next boot to [{:?}], boot_filename to [{:?}], filename to [{:?}]", + self.score.boot_filename, self.score.boot_filename, self.score.filename + ) + ... +```