mirror of https://github.com/telemt/telemt.git
328 lines
13 KiB
Rust
328 lines
13 KiB
Rust
use std::sync::atomic::Ordering;
|
|
|
|
use serde::Serialize;
|
|
|
|
use crate::config::{MeFloorMode, MeWriterPickMode, ProxyConfig, UserMaxUniqueIpsMode};
|
|
use crate::proxy::route_mode::RelayRouteMode;
|
|
|
|
use super::ApiShared;
|
|
use super::runtime_init::build_runtime_startup_summary;
|
|
|
|
#[derive(Serialize)]
|
|
pub(super) struct SystemInfoData {
|
|
pub(super) version: String,
|
|
pub(super) target_arch: String,
|
|
pub(super) target_os: String,
|
|
pub(super) build_profile: String,
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
pub(super) git_commit: Option<String>,
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
pub(super) build_time_utc: Option<String>,
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
pub(super) rustc_version: Option<String>,
|
|
pub(super) process_started_at_epoch_secs: u64,
|
|
pub(super) uptime_seconds: f64,
|
|
pub(super) config_path: String,
|
|
pub(super) config_hash: String,
|
|
pub(super) config_reload_count: u64,
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
pub(super) last_config_reload_epoch_secs: Option<u64>,
|
|
}
|
|
|
|
#[derive(Serialize)]
|
|
pub(super) struct RuntimeGatesData {
|
|
pub(super) accepting_new_connections: bool,
|
|
pub(super) conditional_cast_enabled: bool,
|
|
pub(super) me_runtime_ready: bool,
|
|
pub(super) me2dc_fallback_enabled: bool,
|
|
pub(super) me2dc_fast_enabled: bool,
|
|
pub(super) use_middle_proxy: bool,
|
|
pub(super) route_mode: &'static str,
|
|
pub(super) reroute_active: bool,
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
pub(super) reroute_to_direct_at_epoch_secs: Option<u64>,
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
pub(super) reroute_reason: Option<&'static str>,
|
|
pub(super) startup_status: &'static str,
|
|
pub(super) startup_stage: String,
|
|
pub(super) startup_progress_pct: f64,
|
|
}
|
|
|
|
#[derive(Serialize)]
|
|
pub(super) struct EffectiveTimeoutLimits {
|
|
pub(super) client_handshake_secs: u64,
|
|
pub(super) tg_connect_secs: u64,
|
|
pub(super) client_keepalive_secs: u64,
|
|
pub(super) client_ack_secs: u64,
|
|
pub(super) me_one_retry: u8,
|
|
pub(super) me_one_timeout_ms: u64,
|
|
}
|
|
|
|
#[derive(Serialize)]
|
|
pub(super) struct EffectiveUpstreamLimits {
|
|
pub(super) connect_retry_attempts: u32,
|
|
pub(super) connect_retry_backoff_ms: u64,
|
|
pub(super) connect_budget_ms: u64,
|
|
pub(super) unhealthy_fail_threshold: u32,
|
|
pub(super) connect_failfast_hard_errors: bool,
|
|
}
|
|
|
|
#[derive(Serialize)]
|
|
pub(super) struct EffectiveMiddleProxyLimits {
|
|
pub(super) floor_mode: &'static str,
|
|
pub(super) adaptive_floor_idle_secs: u64,
|
|
pub(super) adaptive_floor_min_writers_single_endpoint: u8,
|
|
pub(super) adaptive_floor_min_writers_multi_endpoint: u8,
|
|
pub(super) adaptive_floor_recover_grace_secs: u64,
|
|
pub(super) adaptive_floor_writers_per_core_total: u16,
|
|
pub(super) adaptive_floor_cpu_cores_override: u16,
|
|
pub(super) adaptive_floor_max_extra_writers_single_per_core: u16,
|
|
pub(super) adaptive_floor_max_extra_writers_multi_per_core: u16,
|
|
pub(super) adaptive_floor_max_active_writers_per_core: u16,
|
|
pub(super) adaptive_floor_max_warm_writers_per_core: u16,
|
|
pub(super) adaptive_floor_max_active_writers_global: u32,
|
|
pub(super) adaptive_floor_max_warm_writers_global: u32,
|
|
pub(super) reconnect_max_concurrent_per_dc: u32,
|
|
pub(super) reconnect_backoff_base_ms: u64,
|
|
pub(super) reconnect_backoff_cap_ms: u64,
|
|
pub(super) reconnect_fast_retry_count: u32,
|
|
pub(super) writer_pick_mode: &'static str,
|
|
pub(super) writer_pick_sample_size: u8,
|
|
pub(super) me2dc_fallback: bool,
|
|
pub(super) me2dc_fast: bool,
|
|
}
|
|
|
|
#[derive(Serialize)]
|
|
pub(super) struct EffectiveUserIpPolicyLimits {
|
|
pub(super) global_each: usize,
|
|
pub(super) mode: &'static str,
|
|
pub(super) window_secs: u64,
|
|
}
|
|
|
|
#[derive(Serialize)]
|
|
pub(super) struct EffectiveLimitsData {
|
|
pub(super) update_every_secs: u64,
|
|
pub(super) me_reinit_every_secs: u64,
|
|
pub(super) me_pool_force_close_secs: u64,
|
|
pub(super) timeouts: EffectiveTimeoutLimits,
|
|
pub(super) upstream: EffectiveUpstreamLimits,
|
|
pub(super) middle_proxy: EffectiveMiddleProxyLimits,
|
|
pub(super) user_ip_policy: EffectiveUserIpPolicyLimits,
|
|
}
|
|
|
|
#[derive(Serialize)]
|
|
pub(super) struct SecurityPostureData {
|
|
pub(super) api_read_only: bool,
|
|
pub(super) api_whitelist_enabled: bool,
|
|
pub(super) api_whitelist_entries: usize,
|
|
pub(super) api_auth_header_enabled: bool,
|
|
pub(super) proxy_protocol_enabled: bool,
|
|
pub(super) log_level: String,
|
|
pub(super) telemetry_core_enabled: bool,
|
|
pub(super) telemetry_user_enabled: bool,
|
|
pub(super) telemetry_me_level: String,
|
|
}
|
|
|
|
pub(super) fn build_system_info_data(
|
|
shared: &ApiShared,
|
|
_cfg: &ProxyConfig,
|
|
revision: &str,
|
|
) -> SystemInfoData {
|
|
let last_reload_epoch_secs = shared
|
|
.runtime_state
|
|
.last_config_reload_epoch_secs
|
|
.load(Ordering::Relaxed);
|
|
let last_config_reload_epoch_secs =
|
|
(last_reload_epoch_secs > 0).then_some(last_reload_epoch_secs);
|
|
|
|
let git_commit = option_env!("TELEMT_GIT_COMMIT")
|
|
.or(option_env!("VERGEN_GIT_SHA"))
|
|
.or(option_env!("GIT_COMMIT"))
|
|
.map(ToString::to_string);
|
|
let build_time_utc = option_env!("BUILD_TIME_UTC")
|
|
.or(option_env!("VERGEN_BUILD_TIMESTAMP"))
|
|
.map(ToString::to_string);
|
|
let rustc_version = option_env!("RUSTC_VERSION")
|
|
.or(option_env!("VERGEN_RUSTC_SEMVER"))
|
|
.map(ToString::to_string);
|
|
|
|
SystemInfoData {
|
|
version: env!("CARGO_PKG_VERSION").to_string(),
|
|
target_arch: std::env::consts::ARCH.to_string(),
|
|
target_os: std::env::consts::OS.to_string(),
|
|
build_profile: option_env!("PROFILE").unwrap_or("unknown").to_string(),
|
|
git_commit,
|
|
build_time_utc,
|
|
rustc_version,
|
|
process_started_at_epoch_secs: shared.runtime_state.process_started_at_epoch_secs,
|
|
uptime_seconds: shared.stats.uptime_secs(),
|
|
config_path: shared.config_path.display().to_string(),
|
|
config_hash: revision.to_string(),
|
|
config_reload_count: shared
|
|
.runtime_state
|
|
.config_reload_count
|
|
.load(Ordering::Relaxed),
|
|
last_config_reload_epoch_secs,
|
|
}
|
|
}
|
|
|
|
pub(super) async fn build_runtime_gates_data(
|
|
shared: &ApiShared,
|
|
cfg: &ProxyConfig,
|
|
) -> RuntimeGatesData {
|
|
let startup_summary = build_runtime_startup_summary(shared).await;
|
|
let route_state = shared.route_runtime.snapshot();
|
|
let route_mode = route_state.mode.as_str();
|
|
let fast_fallback_enabled =
|
|
cfg.general.use_middle_proxy && cfg.general.me2dc_fallback && cfg.general.me2dc_fast;
|
|
let reroute_active = cfg.general.use_middle_proxy
|
|
&& cfg.general.me2dc_fallback
|
|
&& matches!(route_state.mode, RelayRouteMode::Direct);
|
|
let reroute_to_direct_at_epoch_secs = if reroute_active {
|
|
shared.route_runtime.direct_since_epoch_secs()
|
|
} else {
|
|
None
|
|
};
|
|
let reroute_reason = if reroute_active {
|
|
if fast_fallback_enabled {
|
|
Some("fast_not_ready_fallback")
|
|
} else {
|
|
Some("strict_grace_fallback")
|
|
}
|
|
} else {
|
|
None
|
|
};
|
|
let me_runtime_ready = if !cfg.general.use_middle_proxy {
|
|
true
|
|
} else {
|
|
shared
|
|
.me_pool
|
|
.read()
|
|
.await
|
|
.as_ref()
|
|
.map(|pool| pool.is_runtime_ready())
|
|
.unwrap_or(false)
|
|
};
|
|
|
|
RuntimeGatesData {
|
|
accepting_new_connections: shared.runtime_state.admission_open.load(Ordering::Relaxed),
|
|
conditional_cast_enabled: cfg.general.use_middle_proxy,
|
|
me_runtime_ready,
|
|
me2dc_fallback_enabled: cfg.general.me2dc_fallback,
|
|
me2dc_fast_enabled: fast_fallback_enabled,
|
|
use_middle_proxy: cfg.general.use_middle_proxy,
|
|
route_mode,
|
|
reroute_active,
|
|
reroute_to_direct_at_epoch_secs,
|
|
reroute_reason,
|
|
startup_status: startup_summary.status,
|
|
startup_stage: startup_summary.stage,
|
|
startup_progress_pct: startup_summary.progress_pct,
|
|
}
|
|
}
|
|
|
|
pub(super) fn build_limits_effective_data(cfg: &ProxyConfig) -> EffectiveLimitsData {
|
|
EffectiveLimitsData {
|
|
update_every_secs: cfg.general.effective_update_every_secs(),
|
|
me_reinit_every_secs: cfg.general.effective_me_reinit_every_secs(),
|
|
me_pool_force_close_secs: cfg.general.effective_me_pool_force_close_secs(),
|
|
timeouts: EffectiveTimeoutLimits {
|
|
client_handshake_secs: cfg.timeouts.client_handshake,
|
|
tg_connect_secs: cfg.general.tg_connect,
|
|
client_keepalive_secs: cfg.timeouts.client_keepalive,
|
|
client_ack_secs: cfg.timeouts.client_ack,
|
|
me_one_retry: cfg.timeouts.me_one_retry,
|
|
me_one_timeout_ms: cfg.timeouts.me_one_timeout_ms,
|
|
},
|
|
upstream: EffectiveUpstreamLimits {
|
|
connect_retry_attempts: cfg.general.upstream_connect_retry_attempts,
|
|
connect_retry_backoff_ms: cfg.general.upstream_connect_retry_backoff_ms,
|
|
connect_budget_ms: cfg.general.upstream_connect_budget_ms,
|
|
unhealthy_fail_threshold: cfg.general.upstream_unhealthy_fail_threshold,
|
|
connect_failfast_hard_errors: cfg.general.upstream_connect_failfast_hard_errors,
|
|
},
|
|
middle_proxy: EffectiveMiddleProxyLimits {
|
|
floor_mode: me_floor_mode_label(cfg.general.me_floor_mode),
|
|
adaptive_floor_idle_secs: cfg.general.me_adaptive_floor_idle_secs,
|
|
adaptive_floor_min_writers_single_endpoint: cfg
|
|
.general
|
|
.me_adaptive_floor_min_writers_single_endpoint,
|
|
adaptive_floor_min_writers_multi_endpoint: cfg
|
|
.general
|
|
.me_adaptive_floor_min_writers_multi_endpoint,
|
|
adaptive_floor_recover_grace_secs: cfg.general.me_adaptive_floor_recover_grace_secs,
|
|
adaptive_floor_writers_per_core_total: cfg
|
|
.general
|
|
.me_adaptive_floor_writers_per_core_total,
|
|
adaptive_floor_cpu_cores_override: cfg.general.me_adaptive_floor_cpu_cores_override,
|
|
adaptive_floor_max_extra_writers_single_per_core: cfg
|
|
.general
|
|
.me_adaptive_floor_max_extra_writers_single_per_core,
|
|
adaptive_floor_max_extra_writers_multi_per_core: cfg
|
|
.general
|
|
.me_adaptive_floor_max_extra_writers_multi_per_core,
|
|
adaptive_floor_max_active_writers_per_core: cfg
|
|
.general
|
|
.me_adaptive_floor_max_active_writers_per_core,
|
|
adaptive_floor_max_warm_writers_per_core: cfg
|
|
.general
|
|
.me_adaptive_floor_max_warm_writers_per_core,
|
|
adaptive_floor_max_active_writers_global: cfg
|
|
.general
|
|
.me_adaptive_floor_max_active_writers_global,
|
|
adaptive_floor_max_warm_writers_global: cfg
|
|
.general
|
|
.me_adaptive_floor_max_warm_writers_global,
|
|
reconnect_max_concurrent_per_dc: cfg.general.me_reconnect_max_concurrent_per_dc,
|
|
reconnect_backoff_base_ms: cfg.general.me_reconnect_backoff_base_ms,
|
|
reconnect_backoff_cap_ms: cfg.general.me_reconnect_backoff_cap_ms,
|
|
reconnect_fast_retry_count: cfg.general.me_reconnect_fast_retry_count,
|
|
writer_pick_mode: me_writer_pick_mode_label(cfg.general.me_writer_pick_mode),
|
|
writer_pick_sample_size: cfg.general.me_writer_pick_sample_size,
|
|
me2dc_fallback: cfg.general.me2dc_fallback,
|
|
me2dc_fast: cfg.general.me2dc_fast,
|
|
},
|
|
user_ip_policy: EffectiveUserIpPolicyLimits {
|
|
global_each: cfg.access.user_max_unique_ips_global_each,
|
|
mode: user_max_unique_ips_mode_label(cfg.access.user_max_unique_ips_mode),
|
|
window_secs: cfg.access.user_max_unique_ips_window_secs,
|
|
},
|
|
}
|
|
}
|
|
|
|
pub(super) fn build_security_posture_data(cfg: &ProxyConfig) -> SecurityPostureData {
|
|
SecurityPostureData {
|
|
api_read_only: cfg.server.api.read_only,
|
|
api_whitelist_enabled: !cfg.server.api.whitelist.is_empty(),
|
|
api_whitelist_entries: cfg.server.api.whitelist.len(),
|
|
api_auth_header_enabled: !cfg.server.api.auth_header.is_empty(),
|
|
proxy_protocol_enabled: cfg.server.proxy_protocol,
|
|
log_level: cfg.general.log_level.to_string(),
|
|
telemetry_core_enabled: cfg.general.telemetry.core_enabled,
|
|
telemetry_user_enabled: cfg.general.telemetry.user_enabled,
|
|
telemetry_me_level: cfg.general.telemetry.me_level.to_string(),
|
|
}
|
|
}
|
|
|
|
fn user_max_unique_ips_mode_label(mode: UserMaxUniqueIpsMode) -> &'static str {
|
|
match mode {
|
|
UserMaxUniqueIpsMode::ActiveWindow => "active_window",
|
|
UserMaxUniqueIpsMode::TimeWindow => "time_window",
|
|
UserMaxUniqueIpsMode::Combined => "combined",
|
|
}
|
|
}
|
|
|
|
fn me_floor_mode_label(mode: MeFloorMode) -> &'static str {
|
|
match mode {
|
|
MeFloorMode::Static => "static",
|
|
MeFloorMode::Adaptive => "adaptive",
|
|
}
|
|
}
|
|
|
|
fn me_writer_pick_mode_label(mode: MeWriterPickMode) -> &'static str {
|
|
match mode {
|
|
MeWriterPickMode::SortedRr => "sorted_rr",
|
|
MeWriterPickMode::P2c => "p2c",
|
|
}
|
|
}
|