Skip to content

Commit

Permalink
Bridge: load config from string (env var or cli flag) (#999)
Browse files Browse the repository at this point in the history
## Motivation

Writing out config data to disk can sometimes be awkward. Users of the
Bridge docker image would either need to customize, using the bridge
image as a base then add their config file to the fs, or otherwise use a
volume mount (or similar).

k8s users have the benefit of config maps, which can be represented as
files on disk, but this is not always a good option.

## Solution

Allows Bridge to load its config data from a string, which can be
supplied as an env var or directly on the cli with `--cfg`.

The original flag for specifying an alternative file path to read config
data from (formerly `--cfg` or `-c`) has been renamed to `--cfg-file`.

Sorry that's so confusing!

- Use `--cfg` to pass config as string
- Use `--cfg-file` to read from file, non-default loction

Additionally, a naive "search path" has been provided to look for the
default config file using a series of names:

- `svix-bridge.yaml`
- `svix-bridge.yml`
- `svix-bridge.json`

This was done specifically to formalize the fact we're advertising "we
accept json config data" in the readme.
  • Loading branch information
svix-onelson authored Jul 10, 2023
2 parents 55dba4e + dc666ab commit c4c606b
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 20 deletions.
19 changes: 13 additions & 6 deletions bridge/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -123,15 +123,22 @@ If you don't want to use docker, see [Building from Source](../README.md#buildin
# Usage and Configuration
The CLI itself will look for a config file named `svix-bridge.yaml` or `svix-bridge.json` in the current working
directory.
Additionally, Bridge can load its configuration from a different location via `--cfg-file` (or `SVIX_BRIDGE_CFG_FILE`),
or otherwise the config can be given as a string via `--cfg` (or `SVIX_BRIDGE_CFG`).
Examples:
```
$ svix-bridge -c path/to/svix-bridge.yaml
```
# Using the default config file location
$ svix-bridge

The CLI itself exposes only a single flag (`-c`, `--cfg`) used to set the path for the config file.
The location of the config file can also be set with the `SVIX_BRIDGE_CFG` env var.
The config file itself does the heavy lifting.
# Specifying an alternate location
$ svix-bridge --cfg-file path/to/svix-bridge.json

When unset, the current working directory is checked for a file named `svix-bridge.yaml`.
# Config data supplied directly
$ svix-bridge --cfg '{"log_format": "json", "senders": []}'
```
## Variable Expansion
Expand Down
46 changes: 32 additions & 14 deletions bridge/svix-bridge/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -147,27 +147,45 @@ async fn supervise_senders(inputs: Vec<Box<dyn SenderInput>>) -> Result<()> {

#[derive(Parser)]
pub struct Args {
#[arg(short, long, env = "SVIX_BRIDGE_CFG")]
cfg: Option<PathBuf>,
#[arg(long, env = "SVIX_BRIDGE_CFG_FILE", help = "Path to the config file.")]
cfg_file: Option<PathBuf>,
#[arg(
long,
env = "SVIX_BRIDGE_CFG",
help = "Config data as a string (instead of a file on disk).",
conflicts_with = "cfg_file"
)]
cfg: Option<String>,
}

#[tokio::main]
async fn main() -> Result<()> {
let args = Args::parse();

let config_path = args.cfg.unwrap_or_else(|| {
std::env::current_dir()
.expect("current dir")
.join("svix-bridge.yaml")
});
let mut config_search_paths = vec![];

let cfg_source = std::fs::read_to_string(&config_path).map_err(|e| {
let p = config_path
.into_os_string()
.into_string()
.expect("config path");
Error::new(ErrorKind::Other, format!("Failed to read {p}: {e}"))
})?;
if let Some(fp) = args.cfg_file {
config_search_paths.push(fp)
} else {
for name in ["svix-bridge.yaml", "svix-bridge.yml", "svix-bridge.json"] {
config_search_paths.push(std::env::current_dir().expect("current dir").join(name));
}
}

// Clap will ensure we have only one or the other (cfg and cfg_file can't be specified together).
let cfg_source = match args.cfg {
Some(cfg_source) => cfg_source,
None => {
let fp = config_search_paths
.into_iter()
.find(|x| x.exists())
.expect("config file path");
std::fs::read_to_string(&fp).map_err(|e| {
let p = fp.into_os_string().into_string().expect("config file path");
Error::new(ErrorKind::Other, format!("Failed to read {p}: {e}"))
})
}?,
};

let vars = std::env::vars().collect();
let cfg = Config::from_src(&cfg_source, Some(vars).as_ref())?;
Expand Down

0 comments on commit c4c606b

Please sign in to comment.