use std::collections::HashMap;
use lightshuttle_runtime::{ContainerSpec, ImageSource, PortBinding};
pub const SYNTHETIC_RESOURCE_NAME: &str = "lightshuttle_otel";
const DEFAULT_OTLP_GRPC_PORT: u16 = 4317;
const DEFAULT_OTLP_HTTP_PORT: u16 = 4318;
const DEFAULT_IMAGE: &str = "otel/opentelemetry-collector:0.108.0";
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct CollectorConfig {
pub image: String,
pub otlp_grpc_port: u16,
pub otlp_http_port: u16,
}
impl CollectorConfig {
#[must_use]
pub fn defaults() -> Self {
Self {
image: DEFAULT_IMAGE.to_owned(),
otlp_grpc_port: DEFAULT_OTLP_GRPC_PORT,
otlp_http_port: DEFAULT_OTLP_HTTP_PORT,
}
}
#[must_use]
pub fn hostname(&self, project: &str) -> String {
format!("{project}_{SYNTHETIC_RESOURCE_NAME}")
}
#[must_use]
pub fn to_container_spec(&self, project: &str) -> ContainerSpec {
ContainerSpec {
name: format!("{project}_{SYNTHETIC_RESOURCE_NAME}"),
project: project.to_owned(),
resource: SYNTHETIC_RESOURCE_NAME.to_owned(),
image: ImageSource::Pull(self.image.clone()),
env: HashMap::new(),
ports: vec![
PortBinding {
container_port: DEFAULT_OTLP_GRPC_PORT,
host_address: Some("127.0.0.1".to_owned()),
host_port: self.otlp_grpc_port,
},
PortBinding {
container_port: DEFAULT_OTLP_HTTP_PORT,
host_address: Some("127.0.0.1".to_owned()),
host_port: self.otlp_http_port,
},
],
volumes: Vec::new(),
command: None,
healthcheck: None,
working_dir: None,
}
}
}
impl Default for CollectorConfig {
fn default() -> Self {
Self::defaults()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn defaults_match_otlp_standard_ports() {
let cfg = CollectorConfig::defaults();
assert_eq!(cfg.otlp_grpc_port, 4317);
assert_eq!(cfg.otlp_http_port, 4318);
assert!(cfg.image.starts_with("otel/opentelemetry-collector"));
}
#[test]
fn hostname_is_project_prefixed() {
let cfg = CollectorConfig::defaults();
assert_eq!(cfg.hostname("demo"), "demo_lightshuttle_otel");
}
#[test]
fn to_container_spec_publishes_both_otlp_ports() {
let cfg = CollectorConfig::defaults();
let spec = cfg.to_container_spec("demo");
assert_eq!(spec.name, "demo_lightshuttle_otel");
assert_eq!(spec.project, "demo");
assert_eq!(spec.resource, "lightshuttle_otel");
assert_eq!(spec.ports.len(), 2);
let host_ports: Vec<u16> = spec.ports.iter().map(|p| p.host_port).collect();
assert!(host_ports.contains(&4317));
assert!(host_ports.contains(&4318));
}
}