use std::{collections::HashMap, net::IpAddr, path::PathBuf};
use clap::Parser;
use serde::Deserialize;
use crate::entities::{
logger::{LogConfig, LogLevel, StdioLogMode},
Timelength,
};
use super::{
empty_or_redacted, DockerRegistry, GitProvider, ProviderAccount,
};
#[derive(Parser)]
#[command(name = "periphery", author, about, version)]
pub struct CliArgs {
#[arg(short, long)]
pub config_path: Option<Vec<String>>,
#[arg(long)]
pub config_keyword: Option<Vec<String>>,
#[arg(long)]
pub merge_nested_config: Option<bool>,
#[arg(long)]
pub extend_config_arrays: Option<bool>,
#[arg(long)]
pub log_level: Option<tracing::Level>,
}
#[derive(Deserialize)]
pub struct Env {
#[serde(default, alias = "periphery_config_path")]
pub periphery_config_paths: Vec<String>,
#[serde(default, alias = "periphery_config_keyword")]
pub periphery_config_keywords: Vec<String>,
#[serde(default)]
pub periphery_merge_nested_config: bool,
#[serde(default)]
pub periphery_extend_config_arrays: bool,
pub periphery_port: Option<u16>,
pub periphery_repo_dir: Option<PathBuf>,
pub periphery_stack_dir: Option<PathBuf>,
pub periphery_stats_polling_rate: Option<Timelength>,
pub periphery_legacy_compose_cli: Option<bool>,
pub periphery_logging_level: Option<LogLevel>,
pub periphery_logging_stdio: Option<StdioLogMode>,
pub periphery_logging_otlp_endpoint: Option<String>,
pub periphery_logging_opentelemetry_service_name: Option<String>,
pub periphery_allowed_ips: Option<Vec<IpAddr>>,
pub periphery_passkeys: Option<Vec<String>>,
pub periphery_passkeys_file: Option<PathBuf>,
pub periphery_include_disk_mounts: Option<Vec<PathBuf>>,
pub periphery_exclude_disk_mounts: Option<Vec<PathBuf>>,
pub periphery_ssl_enabled: Option<bool>,
pub periphery_ssl_key_file: Option<PathBuf>,
pub periphery_ssl_cert_file: Option<PathBuf>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct PeripheryConfig {
#[serde(default = "default_periphery_port")]
pub port: u16,
#[serde(default = "default_repo_dir")]
pub repo_dir: PathBuf,
#[serde(default = "default_stack_dir")]
pub stack_dir: PathBuf,
#[serde(default = "default_stats_polling_rate")]
pub stats_polling_rate: Timelength,
#[serde(default)]
pub legacy_compose_cli: bool,
#[serde(default)]
pub logging: LogConfig,
#[serde(default)]
pub allowed_ips: Vec<IpAddr>,
#[serde(default)]
pub passkeys: Vec<String>,
#[serde(default)]
pub include_disk_mounts: Vec<PathBuf>,
#[serde(default)]
pub exclude_disk_mounts: Vec<PathBuf>,
#[serde(default)]
pub secrets: HashMap<String, String>,
#[serde(default, alias = "git_provider")]
pub git_providers: Vec<GitProvider>,
#[serde(default, alias = "docker_registry")]
pub docker_registries: Vec<DockerRegistry>,
#[serde(default = "default_ssl_enabled")]
pub ssl_enabled: bool,
#[serde(default = "default_ssl_key_file")]
pub ssl_key_file: PathBuf,
#[serde(default = "default_ssl_cert_file")]
pub ssl_cert_file: PathBuf,
}
fn default_periphery_port() -> u16 {
8120
}
fn default_repo_dir() -> PathBuf {
"/etc/komodo/repos".parse().unwrap()
}
fn default_stack_dir() -> PathBuf {
"/etc/komodo/stacks".parse().unwrap()
}
fn default_stats_polling_rate() -> Timelength {
Timelength::FiveSeconds
}
fn default_ssl_enabled() -> bool {
false
}
fn default_ssl_key_file() -> PathBuf {
"/etc/komodo/ssl/key.pem".parse().unwrap()
}
fn default_ssl_cert_file() -> PathBuf {
"/etc/komodo/ssl/cert.pem".parse().unwrap()
}
impl Default for PeripheryConfig {
fn default() -> Self {
Self {
port: default_periphery_port(),
repo_dir: default_repo_dir(),
stack_dir: default_stack_dir(),
stats_polling_rate: default_stats_polling_rate(),
legacy_compose_cli: Default::default(),
logging: Default::default(),
allowed_ips: Default::default(),
passkeys: Default::default(),
include_disk_mounts: Default::default(),
exclude_disk_mounts: Default::default(),
secrets: Default::default(),
git_providers: Default::default(),
docker_registries: Default::default(),
ssl_enabled: default_ssl_enabled(),
ssl_key_file: default_ssl_key_file(),
ssl_cert_file: default_ssl_cert_file(),
}
}
}
impl PeripheryConfig {
pub fn sanitized(&self) -> PeripheryConfig {
PeripheryConfig {
port: self.port,
repo_dir: self.repo_dir.clone(),
stack_dir: self.stack_dir.clone(),
stats_polling_rate: self.stats_polling_rate,
legacy_compose_cli: self.legacy_compose_cli,
logging: self.logging.clone(),
allowed_ips: self.allowed_ips.clone(),
passkeys: self
.passkeys
.iter()
.map(|passkey| empty_or_redacted(passkey))
.collect(),
include_disk_mounts: self.include_disk_mounts.clone(),
exclude_disk_mounts: self.exclude_disk_mounts.clone(),
secrets: self
.secrets
.iter()
.map(|(var, secret)| {
(var.to_string(), empty_or_redacted(secret))
})
.collect(),
git_providers: self
.git_providers
.iter()
.map(|provider| GitProvider {
domain: provider.domain.clone(),
https: provider.https,
accounts: provider
.accounts
.iter()
.map(|account| ProviderAccount {
username: account.username.clone(),
token: empty_or_redacted(&account.token),
})
.collect(),
})
.collect(),
docker_registries: self
.docker_registries
.iter()
.map(|provider| DockerRegistry {
domain: provider.domain.clone(),
organizations: provider.organizations.clone(),
accounts: provider
.accounts
.iter()
.map(|account| ProviderAccount {
username: account.username.clone(),
token: empty_or_redacted(&account.token),
})
.collect(),
})
.collect(),
ssl_enabled: self.ssl_enabled,
ssl_key_file: self.ssl_key_file.clone(),
ssl_cert_file: self.ssl_cert_file.clone(),
}
}
}