Skip to main content

rustfs_common/
globals.rs

1// Copyright 2024 RustFS Team
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use std::collections::HashMap;
16use std::sync::LazyLock;
17use std::sync::atomic::{AtomicU64, Ordering};
18use tokio::sync::RwLock;
19use tonic::transport::Channel;
20
21pub static GLOBAL_LOCAL_NODE_NAME: LazyLock<RwLock<String>> = LazyLock::new(|| RwLock::new("".to_string()));
22pub static GLOBAL_RUSTFS_HOST: LazyLock<RwLock<String>> = LazyLock::new(|| RwLock::new("".to_string()));
23pub static GLOBAL_RUSTFS_PORT: LazyLock<RwLock<String>> = LazyLock::new(|| RwLock::new("9000".to_string()));
24pub static GLOBAL_RUSTFS_ADDR: LazyLock<RwLock<String>> = LazyLock::new(|| RwLock::new("".to_string()));
25pub static GLOBAL_CONN_MAP: LazyLock<RwLock<HashMap<String, Channel>>> = LazyLock::new(|| RwLock::new(HashMap::new()));
26pub static GLOBAL_ROOT_CERT: LazyLock<RwLock<Option<Vec<u8>>>> = LazyLock::new(|| RwLock::new(None));
27pub static GLOBAL_MTLS_IDENTITY: LazyLock<RwLock<Option<MtlsIdentityPem>>> = LazyLock::new(|| RwLock::new(None));
28pub static GLOBAL_OUTBOUND_TLS_GENERATION: LazyLock<AtomicU64> = LazyLock::new(|| AtomicU64::new(0));
29
30/// Log level to use when reporting cached gRPC connection eviction.
31#[derive(Clone, Copy, Debug, Eq, PartialEq)]
32pub enum ConnectionEvictionLogLevel {
33    Warn,
34    Info,
35    Debug,
36}
37
38/// Set the global local node name.
39///
40/// # Arguments
41/// * `name` - A string slice representing the local node name.
42pub async fn set_global_local_node_name(name: &str) {
43    *GLOBAL_LOCAL_NODE_NAME.write().await = name.to_string();
44}
45
46/// Get the global local node name.
47///
48/// # Returns
49/// * `String` - The local node name.
50pub async fn get_global_local_node_name() -> String {
51    GLOBAL_LOCAL_NODE_NAME.read().await.clone()
52}
53
54/// Read the local node name without waiting for initialization or a writer.
55pub fn try_get_global_local_node_name() -> Option<String> {
56    GLOBAL_LOCAL_NODE_NAME
57        .try_read()
58        .ok()
59        .map(|name| name.clone())
60        .filter(|name| !name.is_empty())
61}
62
63/// Set the global RustFS address used for gRPC connections.
64///
65/// # Arguments
66/// * `addr` - A string slice representing the RustFS address (e.g., "https://node1:9000").
67pub async fn set_global_addr(addr: &str) {
68    *GLOBAL_RUSTFS_ADDR.write().await = addr.to_string();
69}
70
71/// Get the global RustFS host.
72pub async fn get_global_rustfs_host() -> String {
73    GLOBAL_RUSTFS_HOST.read().await.clone()
74}
75
76/// Get the global RustFS address used for gRPC connections.
77pub async fn get_global_addr() -> String {
78    GLOBAL_RUSTFS_ADDR.read().await.clone()
79}
80
81/// Set the global root CA certificate for outbound gRPC clients.
82/// This certificate is used to validate server TLS certificates.
83/// When set to None, clients use the system default root CAs.
84///
85/// # Arguments
86/// * `cert` - A vector of bytes representing the PEM-encoded root CA certificate.
87pub async fn set_global_root_cert(cert: Vec<u8>) {
88    *GLOBAL_ROOT_CERT.write().await = Some(cert);
89}
90
91/// Clear the global root CA certificate for outbound gRPC clients.
92pub async fn clear_global_root_cert() {
93    *GLOBAL_ROOT_CERT.write().await = None;
94}
95
96/// Get the global root CA certificate for outbound gRPC clients.
97pub async fn get_global_root_cert() -> Option<Vec<u8>> {
98    GLOBAL_ROOT_CERT.read().await.clone()
99}
100
101/// Set the global mTLS identity (cert+key PEM) for outbound gRPC clients.
102/// When set, clients will present this identity to servers requesting/requiring mTLS.
103/// When None, clients proceed with standard server-authenticated TLS.
104///
105/// # Arguments
106/// * `identity` - An optional MtlsIdentityPem struct containing the cert and key PEM.
107pub async fn set_global_mtls_identity(identity: Option<MtlsIdentityPem>) {
108    *GLOBAL_MTLS_IDENTITY.write().await = identity;
109}
110
111/// Get the global mTLS identity for outbound gRPC clients.
112pub async fn get_global_mtls_identity() -> Option<MtlsIdentityPem> {
113    GLOBAL_MTLS_IDENTITY.read().await.clone()
114}
115
116/// Set the global outbound TLS generation.
117pub fn set_global_outbound_tls_generation(generation: u64) {
118    GLOBAL_OUTBOUND_TLS_GENERATION.store(generation, Ordering::Relaxed);
119}
120
121/// Get the global outbound TLS generation.
122pub fn get_global_outbound_tls_generation() -> u64 {
123    GLOBAL_OUTBOUND_TLS_GENERATION.load(Ordering::Relaxed)
124}
125
126/// Evict a stale/dead connection from the global connection cache.
127/// This is critical for cluster recovery when a node dies unexpectedly (e.g., power-off).
128/// By removing the cached connection, subsequent requests will establish a fresh connection.
129///
130/// # Arguments
131/// * `addr` - The address of the connection to evict.
132pub async fn evict_connection(addr: &str) {
133    evict_connection_with_log_level(addr, ConnectionEvictionLogLevel::Info).await;
134}
135
136/// Evict a stale/dead connection from the global connection cache with an explicit log level.
137pub async fn evict_connection_with_log_level(addr: &str, log_level: ConnectionEvictionLogLevel) {
138    let removed = GLOBAL_CONN_MAP.write().await.remove(addr);
139    if removed.is_some() {
140        match log_level {
141            ConnectionEvictionLogLevel::Warn => {
142                tracing::warn!(
143                    addr = %addr,
144                    "Removed cached gRPC connection so future RPCs will attempt to establish a fresh channel"
145                );
146            }
147            ConnectionEvictionLogLevel::Info => {
148                tracing::info!(
149                    addr = %addr,
150                    "Removed cached gRPC connection so future RPCs will attempt to establish a fresh channel"
151                );
152            }
153            ConnectionEvictionLogLevel::Debug => {
154                tracing::debug!(
155                    addr = %addr,
156                    "Removed cached gRPC connection so future RPCs will attempt to establish a fresh channel"
157                );
158            }
159        }
160    }
161}
162
163/// Get a cached gRPC connection for the given address.
164pub async fn cached_connection(addr: &str) -> Option<Channel> {
165    GLOBAL_CONN_MAP.read().await.get(addr).cloned()
166}
167
168/// Cache a gRPC connection for the given address.
169pub async fn cache_connection(addr: String, channel: Channel) {
170    GLOBAL_CONN_MAP.write().await.insert(addr, channel);
171}
172
173/// Check if a connection exists in the cache for the given address.
174///
175/// # Arguments
176/// * `addr` - The address to check.
177///
178/// # Returns
179/// * `bool` - True if a cached connection exists, false otherwise.
180pub async fn has_cached_connection(addr: &str) -> bool {
181    GLOBAL_CONN_MAP.read().await.contains_key(addr)
182}
183
184/// Clear all cached connections. Useful for full cluster reset/recovery.
185pub async fn clear_all_connections() {
186    let mut map = GLOBAL_CONN_MAP.write().await;
187    let count = map.len();
188    map.clear();
189    if count > 0 {
190        tracing::warn!("Cleared {} cached connections from global map", count);
191    }
192}
193/// Optional client identity (cert+key PEM) for outbound mTLS.
194///
195/// When present, gRPC clients will present this identity to servers requesting/requiring mTLS.
196/// When absent, clients proceed with standard server-authenticated TLS.
197#[derive(Clone, Debug)]
198pub struct MtlsIdentityPem {
199    pub cert_pem: Vec<u8>,
200    pub key_pem: Vec<u8>,
201}