diff --git a/.env.example b/.env.example index 48454f1..2a5ce55 100644 --- a/.env.example +++ b/.env.example @@ -1,2 +1,2 @@ DATABASE_URL=postgres://postgres@127.0.0.1/vssv -LISTEN_URL=[::1]:3000 +LISTEN_ADDR=[::1]:3000 diff --git a/Cargo.lock b/Cargo.lock index 5649912..a7d4d09 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -217,7 +217,7 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "00c055ee2d014ae5981ce1016374e8213682aa14d9bf40e48ab48b5f3ef20eaa" dependencies = [ - "heck", + "heck 0.4.1", "proc-macro2", "quote", "syn 2.0.66", @@ -325,6 +325,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a9689a29b593160de5bc4aacab7b5d54fb52231de70122626c178e6a368994c7" dependencies = [ "clap_builder", + "clap_derive", ] [[package]] @@ -339,6 +340,18 @@ dependencies = [ "strsim", ] +[[package]] +name = "clap_derive" +version = "4.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c780290ccf4fb26629baa7a1081e68ced113f1d3ec302fa5948f1c381ebf06c6" +dependencies = [ + "heck 0.5.0", + "proc-macro2", + "quote", + "syn 2.0.66", +] + [[package]] name = "clap_lex" version = "0.7.1" @@ -666,6 +679,12 @@ dependencies = [ "unicode-segmentation", ] +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + [[package]] name = "hermit-abi" version = "0.3.9" @@ -1545,7 +1564,7 @@ checksum = "5833ef53aaa16d860e92123292f1f6a3d53c34ba8b1969f152ef1a7bb803f3c8" dependencies = [ "dotenvy", "either", - "heck", + "heck 0.4.1", "hex", "once_cell", "proc-macro2", @@ -2012,14 +2031,13 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "vssv" -version = "1.0.0" +version = "1.1.0" dependencies = [ "anyhow", "axum", "axum-extra", "chrono", "clap", - "dotenvy", "num_cpus", "serde", "sqlx", diff --git a/Cargo.toml b/Cargo.toml index 66ae6cc..b1d4c15 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,7 +4,7 @@ description = "A very simple secrets vault." authors = ["Dennis Schubert "] repository = "https://github.com/denschub/vssv" license = "MIT" -version = "1.0.0" +version = "1.1.0" edition = "2021" [profile.release] @@ -15,8 +15,7 @@ anyhow = "1" axum = { version = "0.7", features = ["macros"] } axum-extra = { version = "0.9", features = ["typed-header"] } chrono = "0.4" -clap = "4" -dotenvy = "0.15" +clap = { version = "4", features = ["derive", "env"] } num_cpus = "1" serde = { version = "1", features = ["derive"] } sqlx = { version = "0.7", features = [ diff --git a/Changelog.md b/Changelog.md index 48ec9a3..040e310 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,3 +1,7 @@ +# 1.1.0 + +This release allows using CLI flags in addition to environment variables to configure `vssv`. + # 1.0.0 The first public release. Changes are: everything and nothing. diff --git a/Dockerfile b/Dockerfile index 7d2b3c9..731ffe3 100644 --- a/Dockerfile +++ b/Dockerfile @@ -19,7 +19,7 @@ RUN \ USER app:app COPY --from=builder /app/out/bin/vssv /app -ENV LISTEN_URL [::]:3000 +ENV LISTEN_ADDR [::]:3000 EXPOSE 3000 HEALTHCHECK CMD curl -f http://localhost:3000/readyz || exit 1 CMD ["/app/vssv"] diff --git a/README.md b/README.md index a5128f5..0cca409 100644 --- a/README.md +++ b/README.md @@ -114,9 +114,9 @@ First, scroll back up and re-read the "You don't want to use this." section. But if you have to, there is a container image [in the GitHub Container registry at `ghcr.io/denschub/vssv:latest`](https://github.com/denschub/vssv/pkgs/container/vssv), and [on Docker Hub as `denschub/vssv:latest`](https://hub.docker.com/repository/docker/denschub/vssv/general). The container exposes port 3000. -Make sure to set the `DATABASE_URL` environment variable to a valid PostgreSQL connection URL like `postgres://postgres@127.0.0.1/vssv`. The database needs to exist before starting the server, but the server startup procedure will take care of all database migrations. +Configuration of the server is done with either environment variables or via CLI arguments. Make sure to set `DATABASE_URL`/`--database-url` to a valid PostgreSQL connection URL like `postgres://postgres@127.0.0.1/vssv`. The database needs to exist before starting the server, but the server startup procedure will take care of all database migrations. -Released binaries are available for all stable releases. Check the [Releases section on GitHub](https://github.com/denschub/vssv/releases) for the latest release, and you'll find a `.zip` with a pre-built binary. If you run the binary yourself, also make sure to set the `[::1]:3000` environment variable to a valid listen address, like `[::1]:3000`, for example. +Released binaries are available for all stable releases. Check the [Releases section on GitHub](https://github.com/denschub/vssv/releases) for the latest release, and you'll find a `.zip` with a pre-built binary. If you run the binary yourself, also make sure to set `LISTEN_ADDR`/`--listen-addr` to a valid listen address, like `[::1]:3000`, for example. You can also build a binary yourself if you have the latest stable Rust toolchain installed. Simply run `cargo build --release`, and you'll find a ready-to-use binary at `target/release/vssv`. diff --git a/src/lib.rs b/src/lib.rs index 287c548..09a958d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,9 +1,24 @@ -use sqlx::PgPool; +use std::net::SocketAddr; + +use sqlx::{postgres::PgConnectOptions, PgPool}; pub mod errors; pub mod models; pub mod routes; +#[derive(Debug, clap::Parser)] +#[clap(about, version, propagate_version = true)] +pub struct Cli { + /// The database URL to connect to. Needs to be a valid PostgreSQL + /// connection URL, like `postgres://postgres@127.0.0.1/vssv` + #[clap(long, short, env = "DATABASE_URL")] + pub database_url: PgConnectOptions, + + /// The Socket Address the server should listen on + #[clap(long, short, env = "LISTEN_ADDR", default_value = "[::1]:3000")] + pub listen_addr: SocketAddr, +} + /// Holds the web server's state. #[derive(Clone)] pub struct ServerState { diff --git a/src/main.rs b/src/main.rs index 122bfb5..c468775 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,12 +1,14 @@ -use std::{env, net::SocketAddr}; +use std::net::SocketAddr; -use anyhow::Context; -use dotenvy::dotenv; -use sqlx::{postgres::PgPoolOptions, PgPool}; +use clap::Parser; +use sqlx::{ + postgres::{PgConnectOptions, PgPoolOptions}, + PgPool, +}; use tokio::{net::TcpListener, signal}; use tracing::info; -use vssv::{routes::build_router, ServerState}; +use vssv::{routes::build_router, Cli, ServerState}; /// Listens to SIGINT (aka ctrl-c) and SIGTERM and completes whenever one of /// those signals happen. @@ -33,32 +35,29 @@ async fn shutdown_signal() { /// Creates a [PgPool] if possible. The pool has its max_connections value set /// to the number of CPUs available. -pub async fn get_db_pool(db_url: &str) -> Result { +pub async fn get_db_pool(connect_options: PgConnectOptions) -> Result { PgPoolOptions::new() .max_connections( num_cpus::get() .try_into() .expect("number of CPU cores should fit into an u32"), ) - .connect(db_url) + .connect_with(connect_options) .await } #[tokio::main] async fn main() -> anyhow::Result<()> { + let cli = Cli::parse(); tracing_subscriber::fmt::init(); - dotenv().ok(); - let database_url = env::var("DATABASE_URL").context("DATABASE_URL must be set")?; - let listen_url = env::var("LISTEN_URL").context("LISTEN_URL must be set")?; - - let db_pool = get_db_pool(&database_url).await?; + let db_pool = get_db_pool(cli.database_url).await?; sqlx::migrate!().run(&db_pool).await?; let router = build_router(ServerState { database: db_pool }); - let listener = TcpListener::bind(listen_url).await?; + let listener = TcpListener::bind(cli.listen_addr).await?; - info!("Will start to listen on `{}`...", listener.local_addr()?); + info!("Will start to listen on `{}`...", cli.listen_addr); axum::serve( listener, router.into_make_service_with_connect_info::(),