refactor: centralize startup runtime bootstrap (#3457)

This commit is contained in:
安正超
2026-06-15 07:57:36 +08:00
committed by GitHub
parent 73e534682e
commit 2288b1bb63
4 changed files with 206 additions and 127 deletions
+1
View File
@@ -70,6 +70,7 @@ pub mod server;
pub mod startup_fs_guard;
pub mod startup_iam;
pub mod startup_protocols;
pub mod startup_runtime;
pub mod startup_services;
pub mod storage;
pub(crate) mod table_catalog;
+3 -101
View File
@@ -19,7 +19,7 @@ use rustfs::init::{
use futures_util::future::join_all;
use rustfs::capacity::capacity_integration::init_capacity_management;
use rustfs::license::{init_license, license_status};
use rustfs::license::init_license;
use rustfs::server::{
ServiceState, ServiceStateManager, ShutdownHandle, ShutdownSignal, shutdown_event_notifier, start_http_server,
stop_audit_system, wait_for_shutdown,
@@ -27,6 +27,7 @@ use rustfs::server::{
use rustfs::startup_fs_guard::enforce_unsupported_fs_policy;
use rustfs::startup_iam::{bootstrap_or_defer_iam_init, publish_ready_for_iam_bootstrap};
use rustfs::startup_protocols::{ProtocolShutdownSenders, init_protocol_shutdown_senders};
use rustfs::startup_runtime::init_startup_runtime_foundation;
use rustfs_common::{GlobalReadiness, SystemStage, set_global_addr};
use rustfs_credentials::init_global_action_credentials;
use rustfs_ecstore::store::init_lock_clients;
@@ -54,7 +55,6 @@ use rustfs_storage_api::BucketOptions;
use rustfs_utils::{
ExternalEnvCompatReport, apply_external_env_compat, get_env_bool_with_aliases, net::parse_and_resolve_address,
};
use rustls::crypto::aws_lc_rs::default_provider;
use std::io::{Error, Result};
use std::sync::Arc;
use tokio_util::sync::CancellationToken;
@@ -66,16 +66,11 @@ const ENV_HEAL_ENABLED: &str = "RUSTFS_HEAL_ENABLED";
const ENV_HEAL_ENABLED_DEPRECATED: &str = "RUSTFS_ENABLE_HEAL";
const LOG_COMPONENT_MAIN: &str = "main";
const LOG_SUBSYSTEM_STARTUP: &str = "startup";
const LOG_SUBSYSTEM_LICENSE: &str = "license";
const LOG_SUBSYSTEM_AUTH: &str = "auth";
const LOG_SUBSYSTEM_STORAGE: &str = "storage";
const EVENT_EXTERNAL_ENV_COMPAT_CONFLICT: &str = "external_env_compat_conflict";
const EVENT_EXTERNAL_ENV_COMPAT_APPLIED: &str = "external_env_compat_applied";
const EVENT_DIAL9_RUNTIME_STATUS: &str = "dial9_runtime_status";
const EVENT_RUNTIME_LICENSE_STATUS: &str = "runtime_license_status";
const EVENT_OBSERVABILITY_GUARD_SET_FAILED: &str = "observability_guard_set_failed";
const EVENT_TLS_OUTBOUND_INITIALIZED: &str = "tls_outbound_initialized";
const EVENT_TLS_OUTBOUND_INITIALIZATION_FAILED: &str = "tls_outbound_initialization_failed";
const EVENT_DEFAULT_CREDENTIALS_DETECTED: &str = "default_credentials_detected";
const EVENT_SERVER_CONFIG_SANITIZED: &str = "server_config_sanitized";
const EVENT_SERVER_STARTING: &str = "server_starting";
@@ -83,7 +78,6 @@ const EVENT_SERVER_RUNTIME_FAILED: &str = "server_runtime_failed";
const EVENT_ACTION_CREDENTIALS_INITIALIZED: &str = "action_credentials_initialized";
const EVENT_ACTION_CREDENTIALS_INITIALIZATION_FAILED: &str = "action_credentials_initialization_failed";
const EVENT_OBSERVABILITY_GUARD_SET: &str = "observability_guard_set";
const EVENT_CRYPTO_PROVIDER_STATE: &str = "crypto_provider_state";
const EVENT_ENDPOINT_PARSING_STARTED: &str = "endpoint_parsing_started";
const EVENT_STARTUP_STORAGE_STAGE: &str = "startup_storage_stage";
const EVENT_STORAGE_POOL_FORMATTING: &str = "storage_pool_formatting";
@@ -217,99 +211,7 @@ async fn async_main() -> Result<()> {
}
log_external_prefix_compat_report(&env_compat_report);
// Check dial9 Tokio runtime telemetry status
// Note: The actual telemetry session is created in build_tokio_runtime()
// which stores the TelemetryGuard globally for the program duration.
if rustfs_obs::dial9::is_enabled() {
info!(
target: "rustfs::main",
event = EVENT_DIAL9_RUNTIME_STATUS,
component = LOG_COMPONENT_MAIN,
subsystem = LOG_SUBSYSTEM_STARTUP,
enabled = true,
"Dial9 Tokio runtime telemetry is enabled"
);
} else {
debug!(
target: "rustfs::main",
event = EVENT_DIAL9_RUNTIME_STATUS,
component = LOG_COMPONENT_MAIN,
subsystem = LOG_SUBSYSTEM_STARTUP,
enabled = false,
"Dial9 Tokio runtime telemetry is disabled"
);
}
info!(
target: "rustfs::main",
event = EVENT_RUNTIME_LICENSE_STATUS,
component = LOG_COMPONENT_MAIN,
subsystem = LOG_SUBSYSTEM_LICENSE,
license_status = %license_status(),
"Initialized runtime license state"
);
// print startup logo
debug!("{}", rustfs::server::LOGO);
// Initialize performance profiling if enabled
rustfs::profiling::init_from_env().await;
// Initialize trusted proxies system
rustfs_trusted_proxies::init();
// Make sure to use a modern encryption suite
if default_provider().install_default().is_err() {
// A crypto provider is already installed (e.g. by the host process); this is fine.
debug!(
target: "rustfs::main",
event = EVENT_CRYPTO_PROVIDER_STATE,
component = LOG_COMPONENT_MAIN,
subsystem = LOG_SUBSYSTEM_STARTUP,
provider = "aws_lc_rs",
state = "already_installed",
"Rustls crypto provider state checked"
);
}
// Initialize TLS outbound material (root CAs, mTLS identity) if configured.
// Server-side TLS acceptor is built separately inside start_http_server().
// Single load via tls-runtime; outbound is enriched with platform CAs and
// published to the global state before any HTTP listener starts.
if let Some(tls_path) = config.tls_path.as_deref().map(str::trim).filter(|path| !path.is_empty()) {
match rustfs::server::tls_material::load_tls_material(tls_path).await {
Ok(snapshot) => {
use rustfs_tls_runtime::{TlsGeneration, publish_global_outbound_tls_state, record_tls_generation};
let generation = TlsGeneration(rustfs_common::get_global_outbound_tls_generation().saturating_add(1));
publish_global_outbound_tls_state(generation, &snapshot.outbound).await;
record_tls_generation("rustfs_server_startup", generation.0);
info!(
target: "rustfs::main",
event = EVENT_TLS_OUTBOUND_INITIALIZED,
component = LOG_COMPONENT_MAIN,
subsystem = LOG_SUBSYSTEM_STARTUP,
tls_path,
generation = generation.0,
"Initialized TLS outbound material"
);
}
Err(e) => {
error!(
target: "rustfs::main",
event = EVENT_TLS_OUTBOUND_INITIALIZATION_FAILED,
component = LOG_COMPONENT_MAIN,
subsystem = LOG_SUBSYSTEM_STARTUP,
tls_path,
error = %e,
"Failed to initialize TLS outbound material"
);
return Err(Error::other(e.to_string()));
}
}
if rustfs_obs::observability_metric_enabled() {
rustfs_tls_runtime::init_tls_metrics();
}
}
init_startup_runtime_foundation(&config).await?;
// Run parameters
match run(*config).await {
+158
View File
@@ -0,0 +1,158 @@
// Copyright 2024 RustFS Team
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use crate::{config::Config, license::license_status};
use rustls::crypto::aws_lc_rs::default_provider;
use std::io::{Error, Result};
use tracing::{debug, error, info};
const LOG_COMPONENT_MAIN: &str = "main";
const LOG_SUBSYSTEM_LICENSE: &str = "license";
const LOG_SUBSYSTEM_STARTUP: &str = "startup";
const EVENT_CRYPTO_PROVIDER_STATE: &str = "crypto_provider_state";
const EVENT_DIAL9_RUNTIME_STATUS: &str = "dial9_runtime_status";
const EVENT_RUNTIME_LICENSE_STATUS: &str = "runtime_license_status";
const EVENT_TLS_OUTBOUND_INITIALIZED: &str = "tls_outbound_initialized";
const EVENT_TLS_OUTBOUND_INITIALIZATION_FAILED: &str = "tls_outbound_initialization_failed";
const TLS_STARTUP_GENERATION_CONSUMER: &str = "rustfs_server_startup";
pub async fn init_startup_runtime_foundation(config: &Config) -> Result<()> {
log_dial9_runtime_status();
log_runtime_license_status();
debug!("{}", crate::server::LOGO);
crate::profiling::init_from_env().await;
rustfs_trusted_proxies::init();
install_default_crypto_provider();
init_outbound_tls_material(config).await
}
fn log_dial9_runtime_status() {
if rustfs_obs::dial9::is_enabled() {
info!(
target: "rustfs::main",
event = EVENT_DIAL9_RUNTIME_STATUS,
component = LOG_COMPONENT_MAIN,
subsystem = LOG_SUBSYSTEM_STARTUP,
enabled = true,
"Dial9 Tokio runtime telemetry is enabled"
);
} else {
debug!(
target: "rustfs::main",
event = EVENT_DIAL9_RUNTIME_STATUS,
component = LOG_COMPONENT_MAIN,
subsystem = LOG_SUBSYSTEM_STARTUP,
enabled = false,
"Dial9 Tokio runtime telemetry is disabled"
);
}
}
fn log_runtime_license_status() {
info!(
target: "rustfs::main",
event = EVENT_RUNTIME_LICENSE_STATUS,
component = LOG_COMPONENT_MAIN,
subsystem = LOG_SUBSYSTEM_LICENSE,
license_status = %license_status(),
"Initialized runtime license state"
);
}
fn install_default_crypto_provider() {
if default_provider().install_default().is_err() {
debug!(
target: "rustfs::main",
event = EVENT_CRYPTO_PROVIDER_STATE,
component = LOG_COMPONENT_MAIN,
subsystem = LOG_SUBSYSTEM_STARTUP,
provider = "aws_lc_rs",
state = "already_installed",
"Rustls crypto provider state checked"
);
}
}
async fn init_outbound_tls_material(config: &Config) -> Result<()> {
if let Some(tls_path) = normalized_tls_path(config.tls_path.as_deref()) {
match crate::server::tls_material::load_tls_material(tls_path).await {
Ok(snapshot) => {
use rustfs_tls_runtime::{publish_global_outbound_tls_state, record_tls_generation};
let generation = next_tls_generation(rustfs_common::get_global_outbound_tls_generation());
publish_global_outbound_tls_state(generation, &snapshot.outbound).await;
record_tls_generation(TLS_STARTUP_GENERATION_CONSUMER, generation.0);
info!(
target: "rustfs::main",
event = EVENT_TLS_OUTBOUND_INITIALIZED,
component = LOG_COMPONENT_MAIN,
subsystem = LOG_SUBSYSTEM_STARTUP,
tls_path,
generation = generation.0,
"Initialized TLS outbound material"
);
}
Err(err) => {
error!(
target: "rustfs::main",
event = EVENT_TLS_OUTBOUND_INITIALIZATION_FAILED,
component = LOG_COMPONENT_MAIN,
subsystem = LOG_SUBSYSTEM_STARTUP,
tls_path,
error = %err,
"Failed to initialize TLS outbound material"
);
return Err(Error::other(err.to_string()));
}
}
if rustfs_obs::observability_metric_enabled() {
rustfs_tls_runtime::init_tls_metrics();
}
}
Ok(())
}
fn normalized_tls_path(path: Option<&str>) -> Option<&str> {
path.map(str::trim).filter(|value| !value.is_empty())
}
fn next_tls_generation(current: u64) -> rustfs_tls_runtime::TlsGeneration {
rustfs_tls_runtime::TlsGeneration(current.saturating_add(1))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn normalized_tls_path_ignores_empty_values() {
assert_eq!(normalized_tls_path(None), None);
assert_eq!(normalized_tls_path(Some("")), None);
assert_eq!(normalized_tls_path(Some(" ")), None);
}
#[test]
fn normalized_tls_path_trims_configured_path() {
assert_eq!(normalized_tls_path(Some(" /tmp/rustfs-tls ")), Some("/tmp/rustfs-tls"));
}
#[test]
fn next_tls_generation_saturates() {
assert_eq!(next_tls_generation(0).0, 1);
assert_eq!(next_tls_generation(u64::MAX).0, u64::MAX);
}
}