use std::fs::File;
use std::io::Write;
use tempfile::TempDir;
use crate::services::flex::gcl::ToGcl;
#[cfg(feature = "experimental")]
use crate::services::flex::policy_binding::PolicyBindingConfig;
use crate::services::flex::ApiConfig;
#[cfg(feature = "experimental")]
use crate::services::flex::UpstreamServiceConfig;
#[derive(Debug)]
pub struct DynamicFlexConfig {
dir: Result<TempDir, std::io::Error>,
path: String,
apis: Vec<ApiConfig>,
#[cfg(feature = "experimental")]
services: Vec<UpstreamServiceConfig>,
#[cfg(feature = "experimental")]
policy_bindings: Vec<PolicyBindingConfig>,
}
impl Clone for DynamicFlexConfig {
fn clone(&self) -> Self {
let mut cloned = DynamicFlexConfig::new();
for api in self.apis.iter() {
cloned = cloned.with_api(api.clone())
}
#[cfg(feature = "experimental")]
for service in self.services.iter() {
cloned = cloned.with_upstream_service(service.clone())
}
#[cfg(feature = "experimental")]
for policy_bindings in self.policy_bindings.iter() {
cloned = cloned.with_policy_bindings(policy_bindings.clone())
}
cloned
}
}
impl DynamicFlexConfig {
pub fn new() -> Self {
let dir = tempfile::tempdir();
let path = dir
.as_ref()
.map(|dir| dir.path().to_string_lossy().to_string())
.unwrap_or_default();
Self {
dir,
path,
apis: vec![],
#[cfg(feature = "experimental")]
services: vec![],
#[cfg(feature = "experimental")]
policy_bindings: vec![],
}
}
fn dump_config<T: ToGcl>(dir: TempDir, config: &T) -> Result<TempDir, std::io::Error> {
let file_path = dir.path().join(format!("{}.yaml", config.name()));
let mut tmp_file = File::create(&file_path)?;
let gcl = config.to_gcl();
tmp_file.write_all(gcl.as_bytes())?;
tmp_file.flush()?;
log::info!(
"Generated GCL name={} path={}",
config.name(),
file_path.display()
);
log::info!("\n{gcl}");
Ok(dir)
}
pub fn with_api(self, api_config: ApiConfig) -> Self {
let dir = self.dir.and_then(|d| Self::dump_config(d, &api_config));
let mut apis = self.apis;
apis.push(api_config);
Self { dir, apis, ..self }
}
#[cfg(feature = "experimental")]
pub fn with_upstream_service(self, service_config: UpstreamServiceConfig) -> Self {
let dir = self.dir.and_then(|d| Self::dump_config(d, &service_config));
let mut services = self.services;
services.push(service_config);
Self {
dir,
services,
..self
}
}
#[cfg(feature = "experimental")]
pub fn with_policy_bindings(self, policy_binding: PolicyBindingConfig) -> Self {
let dir = self.dir.and_then(|d| Self::dump_config(d, &policy_binding));
let mut bindings = self.policy_bindings;
bindings.push(policy_binding);
Self {
dir,
policy_bindings: bindings,
..self
}
}
pub fn dirs(&self) -> Result<Vec<(String, String)>, std::io::Error> {
match &self.dir {
Ok(_) => Ok(vec![(self.path.clone(), "_dynamic".to_string())]),
Err(e) => Err(std::io::Error::new(e.kind(), e.to_string())),
}
}
}