Skip to content

Commit

Permalink
Migrate config to figment
Browse files Browse the repository at this point in the history
Signed-off-by: Sergio Castaño Arteaga <[email protected]>
  • Loading branch information
tegioz committed Nov 28, 2024
1 parent e9c9714 commit ae8b5f0
Show file tree
Hide file tree
Showing 14 changed files with 217 additions and 243 deletions.
249 changes: 86 additions & 163 deletions Cargo.lock

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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"] }
2 changes: 1 addition & 1 deletion charts/clowarden/Chart.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
1 change: 0 additions & 1 deletion charts/clowarden/templates/server_secret.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,3 @@ stringData:
github:
enabled: {{ .Values.services.github.enabled }}
organizations: {{ toYaml .Values.organizations | nindent 6 }}
2 changes: 1 addition & 1 deletion charts/clowarden/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ configDir: "/home/clowarden/.config/clowarden"
# Database configuration
db:
host: ""
port: "5432"
port: 5432
dbname: clowarden
user: postgres
password: postgres
Expand Down
1 change: 0 additions & 1 deletion clowarden-cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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 }
Expand Down
1 change: 0 additions & 1 deletion clowarden-core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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 }
Expand Down
27 changes: 20 additions & 7 deletions clowarden-core/src/cfg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<String>,
}

/// Organization configuration.
#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
#[serde(rename_all(deserialize = "camelCase"))]
Expand All @@ -22,11 +32,14 @@ pub struct Legacy {
pub cncf_people_path: Option<String>,
}

/// 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,
}
2 changes: 1 addition & 1 deletion clowarden-server/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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 }
Expand Down
68 changes: 68 additions & 0 deletions clowarden-server/src/cfg.rs
Original file line number Diff line number Diff line change
@@ -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<Vec<Organization>>,
}

impl Config {
/// Create a new Config instance.
pub(crate) fn new(config_file: &Path) -> Result<Self> {
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<BasicAuth>,
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,
}
32 changes: 14 additions & 18 deletions clowarden-server/src/handlers.rs
Original file line number Diff line number Diff line change
@@ -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::{
Expand All @@ -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;
Expand All @@ -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},
Expand Down Expand Up @@ -69,13 +69,13 @@ struct RouterState {

/// Setup HTTP server router.
pub(crate) fn setup_router(
cfg: &Arc<Config>,
cfg: &Config,
db: DynDB,
gh: DynGH,
jobs_tx: mpsc::UnboundedSender<Job>,
) -> Result<Router> {
// 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");
Expand Down Expand Up @@ -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))
Expand All @@ -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)
Expand Down
8 changes: 5 additions & 3 deletions clowarden-server/src/jobs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -132,15 +132,15 @@ pub(crate) fn handler(
services: &HashMap<ServiceName, DynServiceHandler>,
mut jobs_rx: mpsc::UnboundedReceiver<Job>,
cancel_token: CancellationToken,
orgs: Vec<Organization>,
orgs: &Vec<Organization>,
) -> JoinAll<JoinHandle<()>> {
let mut handles = Vec::with_capacity(orgs.len() + 1);
let mut orgs_jobs_tx_channels = HashMap::new();

// 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()));
}
Expand Down Expand Up @@ -355,8 +355,10 @@ impl OrgWorker {
pub(crate) fn scheduler(
jobs_tx: mpsc::UnboundedSender<Job>,
cancel_token: CancellationToken,
orgs: Vec<Organization>,
orgs: &[Organization],
) -> JoinAll<JoinHandle<()>> {
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);
Expand Down
Loading

0 comments on commit ae8b5f0

Please sign in to comment.