Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Migrate config to figment #285

Merged
merged 1 commit into from
Nov 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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