chartered-git configuration file
Diff
Cargo.lock | 1 +
chartered-git/.gitignore | 1 +
chartered-git/Cargo.toml | 1 +
chartered-db/src/lib.rs | 35 +++++++++++++++++++++++++++++++++++
chartered-git/src/config.rs | 9 +++++++++
chartered-git/src/main.rs | 40 +++++++++++++++++++++++++++++++++++++++-
chartered-web/src/config.rs | 1 +
chartered-web/src/main.rs | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++--
book/src/guide/config-reference.md | 40 ++++++++++++++++++++++++++++++++++++++++
9 files changed, 157 insertions(+), 23 deletions(-)
@@ -515,6 +515,7 @@
"thrussh-keys",
"tokio",
"tokio-util",
"toml",
"tracing",
"tracing-subscriber",
"url",
@@ -1,0 +1,1 @@
config.toml
@@ -32,6 +32,7 @@
thrussh-keys = "0.21"
tokio = { version = "1", features = ["full"] }
tokio-util = { version = "0.6", features = ["codec"] }
toml = "0.5"
tracing = "0.1"
tracing-subscriber = "0.2"
url = "2"
@@ -57,8 +57,11 @@
pub type Connection = diesel_tracing::sqlite::InstrumentedSqliteConnection;
#[cfg(feature = "postgres")]
pub type Connection = diesel_tracing::postgres::InstrumentedPostgresConnection;
pub type Connection = diesel_tracing::pg::InstrumentedPgConnection;
#[cfg(all(feature = "sqlite", feature = "postgres"))]
compile_error!("Only one database backend must be enabled using --features [sqlite|postgres]");
#[cfg(not(any(feature = "sqlite", feature = "postgres")))]
compile_error!(
"At least one database backend must be enabled using `--features [sqlite|postgres]`"
@@ -71,16 +74,42 @@
embed_migrations!();
pub fn init() -> Result<ConnectionPool> {
let pool = Pool::new(ConnectionManager::new("chartered.db"))?;
pub fn init(connection_uri: &str) -> Result<ConnectionPool> {
let connection_uri = parse_connection_uri(connection_uri)?;
let pool = Pool::new(ConnectionManager::new(connection_uri))?;
embedded_migrations::run_with_output(&pool.get()?, &mut std::io::stdout())?;
Ok(Arc::new(pool))
}
#[cfg(feature = "sqlite")]
pub fn parse_connection_uri(connection_uri: &str) -> Result<&str> {
if connection_uri.starts_with("sqlite://") {
Ok(connection_uri.trim_start_matches("sqlite://"))
} else {
Err(Error::SqliteConnectionUri)
}
}
#[cfg(feature = "postgres")]
pub fn parse_connection_uri(connection_uri: &str) -> Result<&str> {
if connection_uri.starts_with("postgres://") {
Ok(connection_uri)
} else {
Err(Error::PostgresConnectionUri)
}
}
#[derive(Error, Display, Debug)]
pub enum Error {
SqliteConnectionUri,
* connection_uri must be a postgres connection uri as described in:
* https://www.postgresql.org/docs/9.4/libpq-connect.html#LIBPQ-CONNSTRING
*/
PostgresConnectionUri,
Connection(#[from] diesel::r2d2::PoolError),
@@ -1,0 +1,9 @@
use serde::Deserialize;
use std::net::SocketAddr;
#[derive(Debug, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct Config {
pub bind_address: SocketAddr,
pub database_uri: String,
}
@@ -1,6 +1,7 @@
#![deny(clippy::pedantic)]
#![deny(rust_2018_idioms)]
mod command_handlers;
mod config;
mod generators;
mod tree;
@@ -19,8 +20,9 @@
use arrayvec::ArrayVec;
use bytes::BytesMut;
use clap::Parser;
use futures::future::Future;
use std::{fmt::Write, pin::Pin, sync::Arc};
use std::{fmt::Write, path::PathBuf, pin::Pin, sync::Arc};
use thrussh::{
server::{self, Auth, Session},
ChannelId, CryptoVec,
@@ -30,24 +32,48 @@
use tracing::{debug, error, info, warn, Instrument};
use url::Url;
#[derive(Parser)]
#[clap(version = clap::crate_version!(), author = clap::crate_authors!())]
pub struct Opts {
#[clap(short, long, parse(from_occurrences))]
verbose: i32,
#[clap(short, long)]
config: PathBuf,
}
#[tokio::main]
#[allow(clippy::semicolon_if_nothing_returned)]
async fn main() {
async fn main() -> anyhow::Result<()> {
let opts: Opts = Opts::parse();
std::env::set_var(
"RUST_LOG",
match opts.verbose {
1 => "debug",
2 => "trace",
_ => "info",
},
);
let config: config::Config = toml::from_slice(&std::fs::read(&opts.config)?)?;
tracing_subscriber::fmt::init();
let config = Arc::new(thrussh::server::Config {
let trussh_config = Arc::new(thrussh::server::Config {
methods: thrussh::MethodSet::PUBLICKEY,
keys: vec![key::KeyPair::generate_ed25519().unwrap()],
..thrussh::server::Config::default()
});
let server = Server {
db: chartered_db::init().unwrap(),
db: chartered_db::init(&config.database_uri)?,
};
info!("SSH server listening on {}", config.bind_address);
thrussh::server::run(trussh_config, &config.bind_address.to_string(), server).await?;
thrussh::server::run(config, "127.0.0.1:2233", server)
.await
.unwrap();
Ok(())
}
#[derive(Clone)]
@@ -20,6 +20,7 @@
#[serde(deny_unknown_fields)]
pub struct Config {
pub bind_address: SocketAddr,
pub database_uri: String,
pub storage_uri: String,
pub auth: AuthConfig,
#[serde(deserialize_with = "deserialize_encryption_key")]
@@ -12,10 +12,11 @@
AddExtensionLayer, Router,
};
use clap::Parser;
use std::path::PathBuf;
use std::sync::Arc;
use std::{fmt::Formatter, path::PathBuf, sync::Arc};
use thiserror::Error;
use tower::ServiceBuilder;
use tower_http::cors::{Any, CorsLayer};
use tracing::info;
#[derive(Parser)]
#[clap(version = clap::crate_version!(), author = clap::crate_authors!())]
@@ -56,15 +57,24 @@
#[tokio::main]
#[allow(clippy::semicolon_if_nothing_returned)]
async fn main() {
async fn main() -> Result<(), InitError> {
let opts: Opts = Opts::parse();
let config: config::Config = toml::from_slice(&std::fs::read(&opts.config).unwrap()).unwrap();
let bind_address = config.bind_address;
std::env::set_var(
"RUST_LOG",
match opts.verbose {
1 => "debug",
2 => "trace",
_ => "info",
},
);
let config: config::Config = toml::from_slice(&std::fs::read(&opts.config)?)?;
tracing_subscriber::fmt::init();
let pool = chartered_db::init().unwrap();
let bind_address = config.bind_address;
let pool = chartered_db::init(&config.database_uri)?;
let middleware_stack = ServiceBuilder::new()
.layer_fn(middleware::logging::LoggingMiddleware)
@@ -107,15 +117,39 @@
)
.layer(AddExtensionLayer::new(pool))
.layer(AddExtensionLayer::new(Arc::new(
config.create_oidc_clients().await.unwrap(),
config.create_oidc_clients().await?,
)))
.layer(AddExtensionLayer::new(Arc::new(
config.get_file_system().await.unwrap(),
config.get_file_system().await?,
)))
.layer(AddExtensionLayer::new(Arc::new(config)));
info!("HTTP server listening on {}", bind_address);
axum::Server::bind(&bind_address)
.serve(app.into_make_service_with_connect_info::<std::net::SocketAddr, _>())
.await
.unwrap();
.map_err(|e| InitError::ServerSpawn(Box::new(e)))?;
Ok(())
}
#[derive(Error)]
pub enum InitError {
#[error("Failed to read configuration: {0}")]
ConfigRead(#[from] std::io::Error),
#[error("Failed to parse configuration: {0}")]
ConfigParse(#[from] toml::de::Error),
#[error("Configuration error: {0}")]
Config(#[from] config::Error),
#[error("Database error: {0}")]
Database(#[from] chartered_db::Error),
#[error("Failed to spawn HTTP server: {0}")]
ServerSpawn(Box<dyn std::error::Error>),
}
impl std::fmt::Debug for InitError {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self)
}
}
@@ -1,14 +1,41 @@
# Configuration Reference
An exhaustive list of all configuration values in chartered.
## chartered-web
Configuration files are written in the TOML format, with simple key-value pairs inside of sections (tables). The following
is a quick overview of all settings, with detailed descriptions found below
## chartered-git
### Configuration format
Configuration files are written in the TOML format, with simple key-value pairs inside of sections (tables). The following
is a quick overview of all settings, with detailed descriptions found below
```toml
bind_address = "127.0.0.1:2233"
database_uri = "postgres://user:password@localhost/chartered" # can also be `sqlite://`
```
### Configuration keys
#### `bind_address`
- Type: string
The IP address and port the web server should be bound to.
#### `database_uri`
- Type: string
A connection string for the backing database, either `postgres` or `sqlite`, either in the
format of `postgres://user:password@localhost/chartered` (a [postgres connection URI][pg-uri]),
`sqlite:///path/to/chartered.db` or `sqlite://:memory:`.
[pg-uri]: https://www.postgresql.org/docs/9.4/libpq-connect.html#LIBPQ-CONNSTRING
---
## chartered-web
### Configuration format
```toml
bind_address = "127.0.0.1:8080"
database_uri = "postgres://user:password@localhost/chartered" # can also be `sqlite://`
@@ -33,8 +60,13 @@
The IP address and port the web server should be bound to.
#### `database_uri`
- Type: string
A connection string for the backing database, either `postgres` or `sqlite`, either in the
format of `postgres://user:password@localhost/chartered` (a [postgres connection URI][pg-uri]),
`sqlite:///path/to/chartered.db` or `sqlite://:memory:`.
A JDBC-like connection string for the backing database, either `postgres` or `sqlite`.
[pg-uri]: https://www.postgresql.org/docs/9.4/libpq-connect.html#LIBPQ-CONNSTRING
#### `storage_uri`
- Type: string