Skip to content

Commit

Permalink
Merge pull request #92 from Kuadrant/config
Browse files Browse the repository at this point in the history
CLI
  • Loading branch information
alexsnaps authored Jul 29, 2022
2 parents c15e1d5 + 28aaabf commit 5eb8f1a
Show file tree
Hide file tree
Showing 12 changed files with 592 additions and 392 deletions.
333 changes: 159 additions & 174 deletions Cargo.lock

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion limitador-server/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ actix-rt = "2"
paperclip = { version = "0.7", features = ["actix4"] }
serde = { version = "1", features = ["derive"] }
notify = "5.0.0-pre.15"
serial_test = "0.7.0"
clap = "3.2"

[build-dependencies]
tonic-build = "0.6"
179 changes: 41 additions & 138 deletions limitador-server/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,31 +18,44 @@
// HTTP_API_HOST: host // just to become HTTP_API_HOST:HTTP_API_PORT as &str
// HTTP_API_PORT: port

use std::env;
use log::LevelFilter;

#[derive(Debug)]
pub struct Configuration {
pub limits_file: Option<String>,
pub limits_file: String,
pub storage: StorageConfiguration,
rls_host: String,
rls_port: u16,
http_host: String,
http_port: u16,
pub limit_name_in_labels: bool,
pub log_level: Option<LevelFilter>,
}

impl Configuration {
pub fn from_env() -> Result<Self, ()> {
let rls_port = env::var("ENVOY_RLS_PORT").unwrap_or_else(|_| "8081".to_string());
let http_port = env::var("HTTP_API_PORT").unwrap_or_else(|_| "8080".to_string());
Ok(Self {
limits_file: env::var("LIMITS_FILE").ok(),
storage: storage_config_from_env()?,
rls_host: env::var("ENVOY_RLS_HOST").unwrap_or_else(|_| "0.0.0.0".to_string()),
rls_port: rls_port.parse().expect("Expected a port number!"),
http_host: env::var("HTTP_API_HOST").unwrap_or_else(|_| "0.0.0.0".to_string()),
http_port: http_port.parse().expect("Expected a port number!"),
limit_name_in_labels: env_option_is_enabled("LIMIT_NAME_IN_PROMETHEUS_LABELS"),
})
pub const DEFAULT_RLS_PORT: &'static str = "8081";
pub const DEFAULT_HTTP_PORT: &'static str = "8080";
pub const DEFAULT_IP_BIND: &'static str = "0.0.0.0";

pub fn with(
storage: StorageConfiguration,
limits_file: String,
rls_host: String,
rls_port: u16,
http_host: String,
http_port: u16,
limit_name_in_labels: bool,
) -> Self {
Self {
limits_file,
storage,
rls_host,
rls_port,
http_host,
http_port,
limit_name_in_labels,
log_level: None,
}
}

pub fn rlp_address(&self) -> String {
Expand All @@ -54,48 +67,19 @@ impl Configuration {
}
}

fn storage_config_from_env() -> Result<StorageConfiguration, ()> {
let redis_url = env::var("REDIS_URL");
let infinispan_url = env::var("INFINISPAN_URL");

match (redis_url, infinispan_url) {
(Ok(_), Ok(_)) => Err(()),
(Ok(url), Err(_)) => Ok(StorageConfiguration::Redis(RedisStorageConfiguration {
url,
cache: if env_option_is_enabled("REDIS_LOCAL_CACHE_ENABLED") {
Some(RedisStorageCacheConfiguration {
flushing_period: env::var("REDIS_LOCAL_CACHE_FLUSHING_PERIOD_MS")
.unwrap_or_else(|_| "1".to_string())
.parse()
.expect("Expected an i64"),
max_ttl: env::var("REDIS_LOCAL_CACHE_MAX_TTL_CACHED_COUNTERS_MS")
.unwrap_or_else(|_| "5000".to_string())
.parse()
.expect("Expected an u64"),
ttl_ratio: env::var("REDIS_LOCAL_CACHE_TTL_RATIO_CACHED_COUNTERS")
.unwrap_or_else(|_| "10".to_string())
.parse()
.expect("Expected an u64"),
})
} else {
None
},
})),
(Err(_), Ok(url)) => Ok(StorageConfiguration::Infinispan(
InfinispanStorageConfiguration {
url,
cache: env::var("INFINISPAN_CACHE_NAME").ok(),
consistency: env::var("INFINISPAN_COUNTERS_CONSISTENCY").ok(),
},
)),
_ => Ok(StorageConfiguration::InMemory),
}
}

fn env_option_is_enabled(env_name: &str) -> bool {
match env::var(env_name) {
Ok(value) => value == "1",
Err(_) => false,
#[cfg(test)]
impl Default for Configuration {
fn default() -> Self {
Configuration {
limits_file: "".to_string(),
storage: StorageConfiguration::InMemory,
rls_host: "".to_string(),
rls_port: 0,
http_host: "".to_string(),
http_port: 0,
limit_name_in_labels: false,
log_level: None,
}
}
}

Expand All @@ -117,6 +101,7 @@ pub struct RedisStorageCacheConfiguration {
pub flushing_period: i64,
pub max_ttl: u64,
pub ttl_ratio: u64,
pub max_counters: usize,
}

#[derive(PartialEq, Debug)]
Expand All @@ -125,85 +110,3 @@ pub struct InfinispanStorageConfiguration {
pub cache: Option<String>,
pub consistency: Option<String>,
}

#[cfg(test)]
mod tests {
use crate::config::{Configuration, StorageConfiguration};
use serial_test::serial;
use std::env;

struct VarEnvCleaner {
vars: Vec<String>,
}

impl VarEnvCleaner {
pub fn new() -> Self {
Self { vars: Vec::new() }
}

pub fn set_var(&mut self, k: &str, v: &str) {
self.vars.insert(0, k.to_string());
env::set_var(k, v);
}
}

impl Drop for VarEnvCleaner {
fn drop(&mut self) {
for var in &self.vars {
env::remove_var(var);
}
}
}

#[test]
#[serial]
fn test_config_defaults() {
let config = Configuration::from_env().unwrap();
assert_eq!(config.limits_file, None);
assert_eq!(config.storage, StorageConfiguration::InMemory);
assert_eq!(config.http_address(), "0.0.0.0:8080".to_string());
assert_eq!(config.rlp_address(), "0.0.0.0:8081".to_string());
assert_eq!(config.limit_name_in_labels, false);
}

#[test]
#[serial]
fn test_config_redis_defaults() {
let mut vars = VarEnvCleaner::new();
let url = "redis://127.0.1.1:7654";
vars.set_var("REDIS_URL", url);

let config = Configuration::from_env().unwrap();
assert_eq!(config.limits_file, None);
if let StorageConfiguration::Redis(ref redis_config) = config.storage {
assert_eq!(redis_config.url, url);
assert_eq!(redis_config.cache, None);
} else {
panic!("Should be a Redis config!");
}
assert_eq!(config.http_address(), "0.0.0.0:8080".to_string());
assert_eq!(config.rlp_address(), "0.0.0.0:8081".to_string());
assert_eq!(config.limit_name_in_labels, false);
}

#[test]
#[serial]
fn test_config_infinispan_defaults() {
let mut vars = VarEnvCleaner::new();

let url = "127.0.2.2:9876";
vars.set_var("INFINISPAN_URL", url);
let config = Configuration::from_env().unwrap();
assert_eq!(config.limits_file, None);
if let StorageConfiguration::Infinispan(ref infinispan_config) = config.storage {
assert_eq!(infinispan_config.url, url);
assert_eq!(infinispan_config.cache, None);
assert_eq!(infinispan_config.consistency, None);
} else {
panic!("Should be an Infinispan config!");
}
assert_eq!(config.http_address(), "0.0.0.0:8080".to_string());
assert_eq!(config.rlp_address(), "0.0.0.0:8081".to_string());
assert_eq!(config.limit_name_in_labels, false);
}
}
8 changes: 2 additions & 6 deletions limitador-server/src/envoy_rls/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -196,9 +196,7 @@ mod tests {
async fn test_returns_ok_when_no_limits_apply() {
// No limits saved
let rate_limiter = MyRateLimiter::new(Arc::new(
Limiter::new(Configuration::from_env().unwrap())
.await
.unwrap(),
Limiter::new(Configuration::default()).await.unwrap(),
));

let req = RateLimitRequest {
Expand Down Expand Up @@ -228,9 +226,7 @@ mod tests {
#[tokio::test]
async fn test_returns_unknown_when_domain_is_empty() {
let rate_limiter = MyRateLimiter::new(Arc::new(
Limiter::new(Configuration::from_env().unwrap())
.await
.unwrap(),
Limiter::new(Configuration::default()).await.unwrap(),
));

let req = RateLimitRequest {
Expand Down
19 changes: 5 additions & 14 deletions limitador-server/src/http_api/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -225,11 +225,8 @@ mod tests {

#[actix_rt::test]
async fn test_metrics() {
let rate_limiter: Arc<Limiter> = Arc::new(
Limiter::new(Configuration::from_env().unwrap())
.await
.unwrap(),
);
let rate_limiter: Arc<Limiter> =
Arc::new(Limiter::new(Configuration::default()).await.unwrap());
let data = web::Data::new(rate_limiter);
let app = test::init_service(
App::new()
Expand All @@ -249,9 +246,7 @@ mod tests {

#[actix_rt::test]
async fn test_limits_read() {
let limiter = Limiter::new(Configuration::from_env().unwrap())
.await
.unwrap();
let limiter = Limiter::new(Configuration::default()).await.unwrap();
let namespace = "test_namespace";

let limit = create_test_limit(&limiter, namespace, 10).await;
Expand All @@ -276,9 +271,7 @@ mod tests {

#[actix_rt::test]
async fn test_check_and_report() {
let limiter = Limiter::new(Configuration::from_env().unwrap())
.await
.unwrap();
let limiter = Limiter::new(Configuration::default()).await.unwrap();

// Create a limit with max == 1
let namespace = "test_namespace";
Expand Down Expand Up @@ -324,9 +317,7 @@ mod tests {
#[actix_rt::test]
async fn test_check_and_report_endpoints_separately() {
let namespace = "test_namespace";
let limiter = Limiter::new(Configuration::from_env().unwrap())
.await
.unwrap();
let limiter = Limiter::new(Configuration::default()).await.unwrap();
let _limit = create_test_limit(&limiter, namespace, 1).await;

let rate_limiter: Arc<Limiter> = Arc::new(limiter);
Expand Down
Loading

0 comments on commit 5eb8f1a

Please sign in to comment.