From ae8b5f039bf2410b0a3e947466093b5a5a9005cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergio=20Casta=C3=B1o=20Arteaga?= Date: Thu, 28 Nov 2024 12:16:35 +0100 Subject: [PATCH] Migrate config to figment MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Sergio CastaƱo Arteaga --- Cargo.lock | 249 ++++++------------ Cargo.toml | 4 +- charts/clowarden/Chart.yaml | 2 +- charts/clowarden/templates/server_secret.yaml | 1 - charts/clowarden/values.yaml | 2 +- clowarden-cli/Cargo.toml | 1 - clowarden-core/Cargo.toml | 1 - clowarden-core/src/cfg.rs | 27 +- clowarden-server/Cargo.toml | 2 +- clowarden-server/src/cfg.rs | 68 +++++ clowarden-server/src/handlers.rs | 32 +-- clowarden-server/src/jobs.rs | 8 +- clowarden-server/src/main.rs | 61 ++--- docs/dev.md | 2 +- 14 files changed, 217 insertions(+), 243 deletions(-) create mode 100644 clowarden-server/src/cfg.rs diff --git a/Cargo.lock b/Cargo.lock index 5542f88..97c63e2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17,17 +17,6 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" -[[package]] -name = "ahash" -version = "0.7.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "891477e0c6a8957309ee5c45a6368af3ae14bb510732d2684ffa19af310920f9" -dependencies = [ - "getrandom", - "once_cell", - "version_check", -] - [[package]] name = "ahash" version = "0.8.11" @@ -181,6 +170,15 @@ dependencies = [ "syn 2.0.89", ] +[[package]] +name = "atomic" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d818003e740b63afc82337e3160717f4f63078720a810b7b903e70a5d1d2994" +dependencies = [ + "bytemuck", +] + [[package]] name = "autocfg" version = "1.1.0" @@ -323,6 +321,12 @@ version = "3.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a3e2c3daef883ecc1b5d58c15adae93470a91d425f3532ba1695849656af3fc1" +[[package]] +name = "bytemuck" +version = "1.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b37c88a63ffd85d15b406896cc343916d7cf57838a847b3a6f2ca5d39a5695a" + [[package]] name = "byteorder" version = "1.4.3" @@ -341,7 +345,7 @@ version = "0.54.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9718806c4a2fe9e8a56fd736f97b340dd10ed1be8ed733ed50449f351dc33cae" dependencies = [ - "ahash 0.8.11", + "ahash", "async-trait", "cached_proc_macro", "cached_proc_macro_types", @@ -446,7 +450,6 @@ dependencies = [ "anyhow", "clap", "clowarden-core", - "config", "serde", "serde_yaml", "tokio", @@ -463,7 +466,6 @@ dependencies = [ "async-trait", "base64 0.22.1", "cached", - "config", "futures", "lazy_static", "mockall", @@ -489,8 +491,8 @@ dependencies = [ "cached", "clap", "clowarden-core", - "config", "deadpool-postgres", + "figment", "futures", "hex", "hmac", @@ -535,25 +537,6 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" -[[package]] -name = "config" -version = "0.13.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23738e11972c7643e4ec947840fc463b6a571afcd3e735bdfce7d03c7a784aca" -dependencies = [ - "async-trait", - "json5", - "lazy_static", - "nom", - "pathdiff", - "ron", - "rust-ini", - "serde", - "serde_json", - "toml", - "yaml-rust", -] - [[package]] name = "core-foundation-sys" version = "0.8.3" @@ -734,12 +717,6 @@ dependencies = [ "subtle", ] -[[package]] -name = "dlv-list" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0688c2a7f92e427f44895cd63841bff7b29f8d7a1648b9e7e07a4a365b2e1257" - [[package]] name = "downcast" version = "0.11.0" @@ -779,6 +756,20 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7" +[[package]] +name = "figment" +version = "0.10.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8cb01cd46b0cf372153850f4c6c272d9cbea2da513e07538405148f95bd789f3" +dependencies = [ + "atomic", + "pear", + "serde", + "serde_yaml", + "uncased", + "version_check", +] + [[package]] name = "fnv" version = "1.0.7" @@ -957,9 +948,6 @@ name = "hashbrown" version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" -dependencies = [ - "ahash 0.7.8", -] [[package]] name = "hashbrown" @@ -967,7 +955,7 @@ version = "0.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" dependencies = [ - "ahash 0.8.11", + "ahash", "allocator-api2", ] @@ -1215,6 +1203,12 @@ dependencies = [ "hashbrown 0.14.3", ] +[[package]] +name = "inlinable_string" +version = "0.1.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8fae54786f62fb2918dcfae3d568594e50eb9b5c25bf04371af6fe7516452fb" + [[package]] name = "ipnet" version = "2.7.1" @@ -1245,17 +1239,6 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "json5" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96b0db21af676c1ce64250b5f40f3ce2cf27e4e47cb91ed91eb6fe9350b430c1" -dependencies = [ - "pest", - "pest_derive", - "serde", -] - [[package]] name = "jsonwebtoken" version = "8.2.0" @@ -1297,12 +1280,6 @@ dependencies = [ "cc", ] -[[package]] -name = "linked-hash-map" -version = "0.5.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" - [[package]] name = "lock_api" version = "0.4.11" @@ -1604,16 +1581,6 @@ dependencies = [ "thiserror 1.0.65", ] -[[package]] -name = "ordered-multimap" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccd746e37177e1711c20dd619a1620f34f5c8b569c53590a72dedd5344d8924a" -dependencies = [ - "dlv-list", - "hashbrown 0.12.3", -] - [[package]] name = "overload" version = "0.1.1" @@ -1655,10 +1622,27 @@ dependencies = [ ] [[package]] -name = "pathdiff" -version = "0.2.1" +name = "pear" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8835116a5c179084a830efb3adc117ab007512b535bc1a21c991d3b32a6b44dd" +checksum = "bdeeaa00ce488657faba8ebf44ab9361f9365a97bd39ffb8a60663f57ff4b467" +dependencies = [ + "inlinable_string", + "pear_codegen", + "yansi", +] + +[[package]] +name = "pear_codegen" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4bab5b985dc082b345f812b7df84e1bef27e7207b39e448439ba8bd69c93f147" +dependencies = [ + "proc-macro2", + "proc-macro2-diagnostics", + "quote", + "syn 2.0.89", +] [[package]] name = "pem" @@ -1685,50 +1669,6 @@ version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" -[[package]] -name = "pest" -version = "2.5.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8cbd939b234e95d72bc393d51788aec68aeeb5d51e748ca08ff3aad58cb722f7" -dependencies = [ - "thiserror 1.0.65", - "ucd-trie", -] - -[[package]] -name = "pest_derive" -version = "2.5.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a81186863f3d0a27340815be8f2078dd8050b14cd71913db9fbda795e5f707d7" -dependencies = [ - "pest", - "pest_generator", -] - -[[package]] -name = "pest_generator" -version = "2.5.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75a1ef20bf3193c15ac345acb32e26b3dc3223aff4d77ae4fc5359567683796b" -dependencies = [ - "pest", - "pest_meta", - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "pest_meta" -version = "2.5.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e3b284b1f13a20dc5ebc90aff59a51b8d7137c221131b52a7260c08cbc1cc80" -dependencies = [ - "once_cell", - "pest", - "sha2", -] - [[package]] name = "phf" version = "0.11.2" @@ -1879,6 +1819,19 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "proc-macro2-diagnostics" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af066a9c399a26e020ada66a034357a868728e72cd426f3adcd35f80d88d88c8" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.89", + "version_check", + "yansi", +] + [[package]] name = "quote" version = "1.0.35" @@ -2101,27 +2054,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "ron" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88073939a61e5b7680558e6be56b419e208420c2adb92be54921fa6b72283f1a" -dependencies = [ - "base64 0.13.1", - "bitflags 1.3.2", - "serde", -] - -[[package]] -name = "rust-ini" -version = "0.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6d5f2436026b4f6e79dc829837d467cc7e9a55ee40e750d716713540715a2df" -dependencies = [ - "cfg-if", - "ordered-multimap", -] - [[package]] name = "rustc-demangle" version = "0.1.23" @@ -2663,15 +2595,6 @@ dependencies = [ "tokio", ] -[[package]] -name = "toml" -version = "0.5.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" -dependencies = [ - "serde", -] - [[package]] name = "tower" version = "0.4.13" @@ -2744,9 +2667,9 @@ checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" [[package]] name = "tracing" -version = "0.1.40" +version = "0.1.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" +checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" dependencies = [ "log", "pin-project-lite", @@ -2756,9 +2679,9 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.27" +version = "0.1.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" +checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d" dependencies = [ "proc-macro2", "quote", @@ -2767,9 +2690,9 @@ dependencies = [ [[package]] name = "tracing-core" -version = "0.1.32" +version = "0.1.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" +checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c" dependencies = [ "once_cell", "valuable", @@ -2855,10 +2778,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" [[package]] -name = "ucd-trie" -version = "0.1.5" +name = "uncased" +version = "0.9.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e79c4d996edb816c91e4308506774452e55e95c3c9de07b6729e17e15a5ef81" +checksum = "e1b88fcfe09e89d3866a5c11019378088af2d24c3fbd4f0543f96b479ec90697" +dependencies = [ + "version_check", +] [[package]] name = "unicase" @@ -3257,13 +3183,10 @@ dependencies = [ ] [[package]] -name = "yaml-rust" -version = "0.4.5" +name = "yansi" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85" -dependencies = [ - "linked-hash-map", -] +checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049" [[package]] name = "zerocopy" diff --git a/Cargo.toml b/Cargo.toml index c1df051..3099779 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,8 +22,8 @@ base64 = "0.22.1" cached = { version = "0.54.0", features = ["async"] } clap = { version = "4.5.21", features = ["derive"] } clowarden-core = { path = "../clowarden-core" } -config = "0.13.4" deadpool-postgres = { version = "0.14.0", features = ["serde"] } +figment = { version = "0.10.19", features = ["yaml", "env"] } futures = "0.3.31" hmac = "0.12.1" hex = "0.4.3" @@ -63,6 +63,6 @@ tokio-postgres = { version = "0.7.12", features = [ tokio-util = { version = "0.7.12", features = ["rt"] } tower = "0.5.1" tower-http = { version = "0.6.2", features = ["auth", "fs", "set-header", "trace"] } -tracing = "0.1.40" +tracing = "0.1.41" tracing-subscriber = { version = "0.3.18", features = ["env-filter", "json"] } uuid = { version = "1.11.0", features = ["serde", "v4"] } diff --git a/charts/clowarden/Chart.yaml b/charts/clowarden/Chart.yaml index a6ebada..7bdfaf2 100644 --- a/charts/clowarden/Chart.yaml +++ b/charts/clowarden/Chart.yaml @@ -2,7 +2,7 @@ apiVersion: v2 name: clowarden description: CLOWarden is a tool that manages access to resources across multiple services type: application -version: 0.1.4-0 +version: 0.1.4-1 appVersion: 0.1.3 kubeVersion: ">= 1.19.0-0" home: https://clowarden.io diff --git a/charts/clowarden/templates/server_secret.yaml b/charts/clowarden/templates/server_secret.yaml index 45726b5..59f1ab8 100644 --- a/charts/clowarden/templates/server_secret.yaml +++ b/charts/clowarden/templates/server_secret.yaml @@ -31,4 +31,3 @@ stringData: github: enabled: {{ .Values.services.github.enabled }} organizations: {{ toYaml .Values.organizations | nindent 6 }} - diff --git a/charts/clowarden/values.yaml b/charts/clowarden/values.yaml index 75b8ccb..88af87a 100644 --- a/charts/clowarden/values.yaml +++ b/charts/clowarden/values.yaml @@ -21,7 +21,7 @@ configDir: "/home/clowarden/.config/clowarden" # Database configuration db: host: "" - port: "5432" + port: 5432 dbname: clowarden user: postgres password: postgres diff --git a/clowarden-cli/Cargo.toml b/clowarden-cli/Cargo.toml index 090c358..2b5fb85 100644 --- a/clowarden-cli/Cargo.toml +++ b/clowarden-cli/Cargo.toml @@ -10,7 +10,6 @@ rust-version.workspace = true anyhow = { workspace = true } clap = { workspace = true } clowarden-core = { path = "../clowarden-core" } -config = { workspace = true } serde = { workspace = true } serde_yaml = { workspace = true } tokio = { workspace = true } diff --git a/clowarden-core/Cargo.toml b/clowarden-core/Cargo.toml index 90f30a0..1f3a5b9 100644 --- a/clowarden-core/Cargo.toml +++ b/clowarden-core/Cargo.toml @@ -12,7 +12,6 @@ as-any = { workspace = true } async-trait = { workspace = true } base64 = { workspace = true } cached = { workspace = true } -config = { workspace = true } futures = { workspace = true } lazy_static = { workspace = true } octorust = { workspace = true } diff --git a/clowarden-core/src/cfg.rs b/clowarden-core/src/cfg.rs index 55449f5..f9644fb 100644 --- a/clowarden-core/src/cfg.rs +++ b/clowarden-core/src/cfg.rs @@ -2,6 +2,16 @@ use serde::{Deserialize, Serialize}; +/// GitHub application configuration. +#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)] +#[serde(rename_all(deserialize = "camelCase"))] +pub struct GitHubApp { + pub app_id: i64, + pub private_key: String, + pub webhook_secret: String, + pub webhook_secret_fallback: Option, +} + /// Organization configuration. #[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)] #[serde(rename_all(deserialize = "camelCase"))] @@ -22,11 +32,14 @@ pub struct Legacy { pub cncf_people_path: Option, } -/// GitHub application configuration. -#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)] -#[serde(rename_all(deserialize = "camelCase"))] -pub struct GitHubApp { - pub app_id: i64, - pub private_key: String, - pub webhook_secret: String, +/// Services configuration. +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)] +pub struct Services { + pub github: Service, +} + +/// Service configuration. +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)] +pub struct Service { + pub enabled: bool, } diff --git a/clowarden-server/Cargo.toml b/clowarden-server/Cargo.toml index 40e82a2..523a7a0 100644 --- a/clowarden-server/Cargo.toml +++ b/clowarden-server/Cargo.toml @@ -14,8 +14,8 @@ axum = { workspace = true } cached = { workspace = true } clap = { workspace = true } clowarden-core = { path = "../clowarden-core" } -config = { workspace = true } deadpool-postgres = { workspace = true } +figment = { workspace = true } futures = { workspace = true } hmac = { workspace = true } hex = { workspace = true } diff --git a/clowarden-server/src/cfg.rs b/clowarden-server/src/cfg.rs new file mode 100644 index 0000000..eba0d57 --- /dev/null +++ b/clowarden-server/src/cfg.rs @@ -0,0 +1,68 @@ +//! This module defines some types to represent the configuration. + +use std::path::{Path, PathBuf}; + +use anyhow::Result; +use deadpool_postgres::Config as Db; +use figment::{ + providers::{Env, Format, Serialized, Yaml}, + Figment, +}; +use serde::{Deserialize, Serialize}; + +use clowarden_core::cfg::{GitHubApp, Organization, Services}; + +/// Server configuration. +#[derive(Debug, Clone, Deserialize, Serialize)] +pub(crate) struct Config { + pub db: Db, + pub log: Log, + pub server: HttpServer, + pub services: Services, + pub organizations: Option>, +} + +impl Config { + /// Create a new Config instance. + pub(crate) fn new(config_file: &Path) -> Result { + Figment::new() + .merge(Serialized::default("log.format", "pretty")) + .merge(Serialized::default("server.addr", "127.0.0.1:9000")) + .merge(Yaml::file(config_file)) + .merge(Env::prefixed("CLOWARDEN_").split("_").lowercase(false)) + .extract() + .map_err(Into::into) + } +} + +/// Logs configuration. +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)] +pub(crate) struct Log { + pub format: LogFormat, +} + +/// Format to use in logs. +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)] +#[serde(rename_all(deserialize = "lowercase"))] +pub(crate) enum LogFormat { + Json, + Pretty, +} + +/// Http server configuration. +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)] +#[serde(rename_all(deserialize = "camelCase"))] +pub(crate) struct HttpServer { + pub addr: String, + pub static_path: PathBuf, + pub basic_auth: Option, + pub github_app: GitHubApp, +} + +/// Basic authentication configuration. +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)] +pub(crate) struct BasicAuth { + pub enabled: bool, + pub username: String, + pub password: String, +} diff --git a/clowarden-server/src/handlers.rs b/clowarden-server/src/handlers.rs index 40865b1..a31516a 100644 --- a/clowarden-server/src/handlers.rs +++ b/clowarden-server/src/handlers.rs @@ -1,7 +1,7 @@ //! This module defines the handlers used to process HTTP requests to the //! supported endpoints. -use std::{fmt::Display, path::Path, sync::Arc}; +use std::{fmt::Display, path::Path}; use anyhow::{format_err, Error, Result}; use axum::{ @@ -15,7 +15,6 @@ use axum::{ routing::{get, get_service, post}, Router, }; -use config::{Config, ConfigError}; use hmac::{Hmac, Mac}; use mime::APPLICATION_JSON; use octorust::types::JobStatus; @@ -33,6 +32,7 @@ use tracing::{error, instrument, trace}; use clowarden_core::cfg::Organization; use crate::{ + cfg::Config, db::{DynDB, SearchChangesInput}, github::{self, Ctx, DynGH, Event, EventError, PullRequestEvent, PullRequestEventAction}, jobs::{Job, ReconcileInput, ValidateInput}, @@ -69,13 +69,13 @@ struct RouterState { /// Setup HTTP server router. pub(crate) fn setup_router( - cfg: &Arc, + cfg: &Config, db: DynDB, gh: DynGH, jobs_tx: mpsc::UnboundedSender, ) -> Result { // Setup some paths - let static_path = cfg.get_string("server.staticPath")?; + let static_path = cfg.server.static_path.clone(); let root_index_path = Path::new(&static_path).join("index.html"); let audit_path = Path::new(&static_path).join("audit"); let audit_index_path = audit_path.join("index.html"); @@ -103,20 +103,16 @@ pub(crate) fn setup_router( .fallback_service(get_service(audit_index)); // Setup basic auth - if cfg.get_bool("server.basicAuth.enabled").unwrap_or(false) { - let username = cfg.get_string("server.basicAuth.username")?; - let password = cfg.get_string("server.basicAuth.password")?; - audit_router = audit_router.layer(ValidateRequestHeaderLayer::basic(&username, &password)); + if let Some(basic_auth) = &cfg.server.basic_auth { + if basic_auth.enabled { + audit_router = audit_router.layer(ValidateRequestHeaderLayer::basic( + &basic_auth.username, + &basic_auth.password, + )); + } } // Setup main router - let orgs = cfg.get("organizations")?; - let webhook_secret = cfg.get_string("server.githubApp.webhookSecret")?; - let webhook_secret_fallback = match cfg.get_string("server.githubApp.webhookSecretFallback") { - Ok(secret) => Some(secret), - Err(ConfigError::NotFound(_)) => None, - Err(err) => return Err(err.into()), - }; let router = Router::new() .route("/webhook/github", post(event)) .route("/health-check", get(health_check)) @@ -136,10 +132,10 @@ pub(crate) fn setup_router( .with_state(RouterState { db, gh, - webhook_secret, - webhook_secret_fallback, + webhook_secret: cfg.server.github_app.webhook_secret.clone(), + webhook_secret_fallback: cfg.server.github_app.webhook_secret_fallback.clone(), jobs_tx, - orgs, + orgs: cfg.organizations.clone().unwrap_or_default(), }); Ok(router) diff --git a/clowarden-server/src/jobs.rs b/clowarden-server/src/jobs.rs index 5fc035c..ac5cfe6 100644 --- a/clowarden-server/src/jobs.rs +++ b/clowarden-server/src/jobs.rs @@ -132,7 +132,7 @@ pub(crate) fn handler( services: &HashMap, mut jobs_rx: mpsc::UnboundedReceiver, cancel_token: CancellationToken, - orgs: Vec, + orgs: &Vec, ) -> JoinAll> { let mut handles = Vec::with_capacity(orgs.len() + 1); let mut orgs_jobs_tx_channels = HashMap::new(); @@ -140,7 +140,7 @@ pub(crate) fn handler( // Create a worker for each organization for org in orgs { let (org_jobs_tx, org_jobs_rx) = mpsc::unbounded_channel(); - orgs_jobs_tx_channels.insert(org.name, org_jobs_tx); + orgs_jobs_tx_channels.insert(org.name.clone(), org_jobs_tx); let org_worker = OrgWorker::new(db.clone(), gh.clone(), ghc.clone(), services.clone()); handles.push(org_worker.run(org_jobs_rx, cancel_token.clone())); } @@ -355,8 +355,10 @@ impl OrgWorker { pub(crate) fn scheduler( jobs_tx: mpsc::UnboundedSender, cancel_token: CancellationToken, - orgs: Vec, + orgs: &[Organization], ) -> JoinAll> { + let orgs = orgs.to_vec(); + let scheduler = tokio::spawn(async move { let reconcile_frequency = time::Duration::from_secs(RECONCILE_FREQUENCY); let mut reconcile = time::interval(reconcile_frequency); diff --git a/clowarden-server/src/main.rs b/clowarden-server/src/main.rs index 0c53f06..f745b4f 100644 --- a/clowarden-server/src/main.rs +++ b/clowarden-server/src/main.rs @@ -4,10 +4,10 @@ use std::{collections::HashMap, net::SocketAddr, path::PathBuf, sync::Arc}; use anyhow::{Context, Result}; +use cfg::{Config, LogFormat}; use clap::Parser; -use config::{Config, File}; use db::DynDB; -use deadpool_postgres::{Config as DbConfig, Runtime}; +use deadpool_postgres::Runtime; use futures::future; use github::DynGH; use openssl::ssl::{SslConnector, SslMethod, SslVerifyMode}; @@ -24,6 +24,7 @@ use clowarden_core::{ use crate::db::PgDB; +mod cfg; mod db; mod github; mod handlers; @@ -43,44 +44,36 @@ async fn main() -> Result<()> { let args = Args::parse(); // Setup configuration - let cfg = Config::builder() - .set_default("log.format", "pretty")? - .set_default("server.addr", "127.0.0.1:9000")? - .add_source(File::from(args.config)) - .build() - .context("error setting up configuration")?; - validate_config(&cfg).context("error validating configuration")?; - let cfg = Arc::new(cfg); + let cfg = Config::new(&args.config).context("error setting up configuration")?; // Setup logging if std::env::var_os("RUST_LOG").is_none() { std::env::set_var("RUST_LOG", "clowarden=debug"); } - let s = tracing_subscriber::fmt().with_env_filter(EnvFilter::from_default_env()); - match cfg.get_string("log.format").as_deref() { - Ok("json") => s.json().init(), - _ => s.init(), + let ts = tracing_subscriber::fmt().with_env_filter(EnvFilter::from_default_env()); + match cfg.log.format { + LogFormat::Json => ts.json().init(), + LogFormat::Pretty => ts.init(), }; // Setup database let mut builder = SslConnector::builder(SslMethod::tls())?; builder.set_verify(SslVerifyMode::NONE); let connector = MakeTlsConnector::new(builder.build()); - let db_cfg: DbConfig = cfg.get("db")?; - let pool = db_cfg.create_pool(Some(Runtime::Tokio1), connector)?; + let pool = cfg.db.create_pool(Some(Runtime::Tokio1), connector)?; let db: DynDB = Arc::new(PgDB::new(pool)); // Setup GitHub clients - let gh_app: core::cfg::GitHubApp = cfg.get("server.githubApp")?; - let gh: DynGH = Arc::new(github::GHApi::new(&gh_app).context("error setting up github client")?); + let gh_app = &cfg.server.github_app; + let gh: DynGH = Arc::new(github::GHApi::new(gh_app).context("error setting up github client")?); let ghc: core::github::DynGH = Arc::new( - core::github::GHApi::new_with_app_creds(&gh_app).context("error setting up core github client")?, + core::github::GHApi::new_with_app_creds(gh_app).context("error setting up core github client")?, ); // Setup services handlers let mut services: HashMap = HashMap::new(); - if cfg.get_bool("services.github.enabled").unwrap_or_default() { - let svc = Arc::new(services::github::service::SvcApi::new_with_app_creds(&gh_app)?); + if cfg.services.github.enabled { + let svc = Arc::new(services::github::service::SvcApi::new_with_app_creds(gh_app)?); services.insert( services::github::SERVICE_NAME, Arc::new(services::github::Handler::new(ghc.clone(), svc)), @@ -88,24 +81,17 @@ async fn main() -> Result<()> { } // Setup and launch jobs workers + let orgs = cfg.organizations.clone().unwrap_or_default(); let cancel_token = CancellationToken::new(); let (jobs_tx, jobs_rx) = mpsc::unbounded_channel(); - let jobs_handler = jobs::handler( - &db, - &gh, - &ghc, - &services, - jobs_rx, - cancel_token.clone(), - cfg.get("organizations")?, - ); - let jobs_scheduler = jobs::scheduler(jobs_tx.clone(), cancel_token.clone(), cfg.get("organizations")?); + let jobs_handler = jobs::handler(&db, &gh, &ghc, &services, jobs_rx, cancel_token.clone(), &orgs); + let jobs_scheduler = jobs::scheduler(jobs_tx.clone(), cancel_token.clone(), &orgs); let jobs_workers_done = future::join_all([jobs_handler, jobs_scheduler]); // Setup and launch HTTP server let router = handlers::setup_router(&cfg, db.clone(), gh.clone(), jobs_tx) .context("error setting up http server router")?; - let addr: SocketAddr = cfg.get_string("server.addr")?.parse()?; + let addr: SocketAddr = cfg.server.addr.parse()?; let listener = TcpListener::bind(addr).await?; info!("server started"); info!(%addr, "listening"); @@ -122,17 +108,6 @@ async fn main() -> Result<()> { Ok(()) } -/// Check if the configuration provided is valid. -fn validate_config(cfg: &Config) -> Result<()> { - // Required fields - cfg.get_string("server.addr")?; - cfg.get_string("server.staticPath")?; - let _: core::cfg::GitHubApp = cfg.get("server.githubApp")?; - let _: Vec = cfg.get("organizations")?; - - Ok(()) -} - /// Return a future that will complete when the program is asked to stop via a /// ctrl+c or terminate signal. async fn shutdown_signal() { diff --git a/docs/dev.md b/docs/dev.md index 435a336..93c759d 100644 --- a/docs/dev.md +++ b/docs/dev.md @@ -72,7 +72,7 @@ Once you have a working Rust development environment set up and the audit tool b ```yaml db: host: localhost - port: "5432" + port: 5432 dbname: clowarden user: postgres password: ""