mirror of
https://github.com/rustfs/rustfs.git
synced 2026-08-08 14:23:13 +00:00
refactor: centralize startup runtime bootstrap (#3457)
This commit is contained in:
@@ -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
@@ -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 {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user