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

Add environment variables in the configuration file #148

Merged
merged 4 commits into from
Jun 3, 2019
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
18 changes: 18 additions & 0 deletions CONFIGURATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,3 +56,21 @@ Sonic Configuration
**[store.fst.graph]**

* `consolidate_after` (type: _integer_, allowed: seconds, default: `180`) — Time after which a graph that has pending updates should be consolidated (increase this delay if you encounter high-CPU usage issues when a consolidation task kicks-in; this value should be lower than `store.fst.pool.inactive_after`)

## Environment variables

You are allowed to use **environment variables** in the config file. Please provide it as follows:

```toml
[channel]

auth_password: "${env.SECRET}"
```

And then you can run sonic providing a defined environment variable:

```
$ SECRET=secretphrase ./sonic -c /path/to/config.cfg
```

**It can be used only for string-like values**
12 changes: 7 additions & 5 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,10 @@ byteorder = "1.3"
hashbrown = "0.3"
linked_hash_set = "0.1"
whatlang = "0.7"
regex = "1"

[dev-dependencies]
bitflags = "=1.0.4"

[features]
default = ["alloc-jemalloc"]
Expand Down
25 changes: 19 additions & 6 deletions src/config/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@
// Copyright: 2019, Valerian Saliou <valerian@valeriansaliou.name>
// License: Mozilla Public License v2.0 (MPL v2.0)

use super::defaults;
use super::env_var;
use std::net::SocketAddr;
use std::path::PathBuf;

use super::defaults;

#[derive(Deserialize)]
pub struct Config {
pub server: ConfigServer,
Expand All @@ -18,18 +18,25 @@ pub struct Config {

#[derive(Deserialize)]
pub struct ConfigServer {
#[serde(default = "defaults::server_log_level")]
#[serde(
default = "defaults::server_log_level",
deserialize_with = "env_var::str"
)]
pub log_level: String,
}

#[derive(Deserialize)]
pub struct ConfigChannel {
#[serde(default = "defaults::channel_inet")]
#[serde(
default = "defaults::channel_inet",
deserialize_with = "env_var::socket_addr"
)]
pub inet: SocketAddr,

#[serde(default = "defaults::channel_tcp_timeout")]
pub tcp_timeout: u64,

#[serde(deserialize_with = "env_var::opt_str")]
pub auth_password: Option<String>,
pub search: ConfigChannelSearch,
}
Expand Down Expand Up @@ -60,7 +67,10 @@ pub struct ConfigStore {

#[derive(Deserialize)]
pub struct ConfigStoreKV {
#[serde(default = "defaults::store_kv_path")]
#[serde(
default = "defaults::store_kv_path",
deserialize_with = "env_var::path_buf"
)]
pub path: PathBuf,

#[serde(default = "defaults::store_kv_retain_word_objects")]
Expand Down Expand Up @@ -104,7 +114,10 @@ pub struct ConfigStoreKVDatabase {

#[derive(Deserialize)]
pub struct ConfigStoreFST {
#[serde(default = "defaults::store_fst_path")]
#[serde(
default = "defaults::store_fst_path",
deserialize_with = "env_var::path_buf"
)]
pub path: PathBuf,

pub pool: ConfigStoreFSTPool,
Expand Down
107 changes: 107 additions & 0 deletions src/config/env_var.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
// Sonic
//
// Fast, lightweight and schema-less search backend
// Copyright: 2019, Valerian Saliou <valerian@valeriansaliou.name>
// License: Mozilla Public License v2.0 (MPL v2.0)

use regex::Regex;
use serde::{Deserialize, Deserializer};
use std::net::SocketAddr;
use std::path::PathBuf;

#[derive(Deserialize, PartialEq)]
struct WrappedString(String);

// deserialize String
pub fn str<'de, D>(d: D) -> Result<String, D::Error>
where
D: Deserializer<'de>,
{
let val = String::deserialize(d)?;
match self::is_env_var(&val) {
true => Ok(self::get_env_var(&val)),
false => Ok(val),
}
}

// deserialize wrapped Option<String>
pub fn opt_str<'de, D>(d: D) -> Result<Option<String>, D::Error>
where
D: Deserializer<'de>,
{
Option::<WrappedString>::deserialize(d).map(|opt: Option<WrappedString>| {
opt.map(|x: WrappedString| {
let val = x.0;
match self::is_env_var(&val) {
true => self::get_env_var(&val),
false => val,
}
})
})
}

// deserialize SocketAddr
// It deserializes visitor as a String and after that it parses it to SocketAddr
pub fn socket_addr<'de, D>(d: D) -> Result<SocketAddr, D::Error>
where
D: Deserializer<'de>,
{
let val = String::deserialize(d)?;
match self::is_env_var(&val) {
true => Ok(self::get_env_var(&val).parse().unwrap()),
false => Ok(val.parse().unwrap()),
}
}

// deserialize PathBuf
// It deserializes visitor as a String and after that it parses it to PathBuf
pub fn path_buf<'de, D>(d: D) -> Result<PathBuf, D::Error>
where
D: Deserializer<'de>,
{
let val = String::deserialize(d)?;
match self::is_env_var(&val) {
true => Ok(PathBuf::from(self::get_env_var(&val))),
false => Ok(PathBuf::from(val)),
}
}

// check using regex if provided visitor contains env variable
// pattern - ${env.VARIABLE}
fn is_env_var(s: &str) -> bool {
let re = Regex::new(r"^\$\{env\.\w+\}$").expect("env_var: regex is invalid");
re.is_match(s)
}

// parses visitor to varaible key and read variable using std::env
fn get_env_var(wrapped_key: &str) -> String {
let key: String = String::from(wrapped_key)
.drain(6..(wrapped_key.len() - 1))
.collect();
std::env::var(key.clone()).expect(&format!("env_var: variable '{}' is not set", key))
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn checks_if_visitor_contains_env_var_pattern() {
assert_eq!(self::is_env_var("${env.XXX}"), true);
assert_eq!(self::is_env_var("${env.XXX"), false);
assert_eq!(self::is_env_var("${env.XXX}a"), false);
assert_eq!(self::is_env_var("a${env.XXX}"), false);
assert_eq!(self::is_env_var("{env.XXX}"), false);
assert_eq!(self::is_env_var("$env.XXX}"), false);
assert_eq!(self::is_env_var("${envXXX}"), false);
assert_eq!(self::is_env_var("${.XXX}"), false);
assert_eq!(self::is_env_var("${XXX}"), false);
}

#[test]
fn get_env_variable() {
std::env::set_var("TEST", "test");
assert_eq!(self::get_env_var("${env.TEST}"), "test");
std::env::remove_var("TEST");
}
}
1 change: 1 addition & 0 deletions src/config/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
// License: Mozilla Public License v2.0 (MPL v2.0)

mod defaults;
mod env_var;

pub mod config;
pub mod logger;
Expand Down
1 change: 1 addition & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ extern crate toml;
extern crate twox_hash;
extern crate unicode_segmentation;
extern crate whatlang;
extern crate regex;

#[cfg(feature = "alloc-jemalloc")]
extern crate jemallocator;
Expand Down