feat(scanner): add runtime scanner controls and status (#3203)

* feat(scanner): add runtime scanner controls and status

* fix(scanner): validate persisted scanner config

* docs(scanner): clarify start delay behavior

---------

Co-authored-by: Henry Guo <marshawcoco@users.noreply.github.com>
Co-authored-by: houseme <housemecn@gmail.com>
This commit is contained in:
Henry Guo
2026-06-04 13:16:26 +08:00
committed by GitHub
parent f708c22b0e
commit 6850457707
16 changed files with 1394 additions and 126 deletions
+15
View File
@@ -18,6 +18,7 @@ pub mod com;
pub mod heal;
mod notify;
mod oidc;
mod scanner;
pub mod storageclass;
use crate::error::Result;
@@ -254,6 +255,7 @@ pub fn init() {
let mut kvs = HashMap::new();
// Load storageclass default configuration
kvs.insert(STORAGE_CLASS_SUB_SYS.to_owned(), storageclass::DEFAULT_KVS.clone());
kvs.insert(rustfs_config::SCANNER_SUB_SYS.to_owned(), scanner::DEFAULT_KVS.clone());
// New: Loading default configurations for notify_webhook and notify_mqtt
// Referring subsystem names through constants to improve the readability and maintainability of the code
kvs.insert(NOTIFY_WEBHOOK_SUB_SYS.to_owned(), notify::DEFAULT_NOTIFY_WEBHOOK_KVS.clone());
@@ -283,6 +285,7 @@ pub fn init() {
#[cfg(test)]
mod tests {
use super::*;
use rustfs_config::{DEFAULT_DELIMITER, DEFAULT_SCANNER_SPEED, SCANNER_CYCLE_MAX_OBJECTS, SCANNER_SPEED, SCANNER_SUB_SYS};
#[test]
fn global_server_config_set_and_get_roundtrip() {
@@ -300,4 +303,16 @@ mod tests {
.expect("storage_class should exist");
assert_eq!(sc_kvs.get("standard"), "EC:4");
}
#[test]
fn scanner_defaults_are_registered_for_admin_config() {
init();
let cfg = Config::new();
let scanner_kvs = cfg
.get_value(SCANNER_SUB_SYS, DEFAULT_DELIMITER)
.expect("scanner defaults should exist");
assert_eq!(scanner_kvs.get(SCANNER_SPEED), DEFAULT_SCANNER_SPEED);
assert_eq!(scanner_kvs.get(SCANNER_CYCLE_MAX_OBJECTS), "0");
}
}
+106
View File
@@ -0,0 +1,106 @@
// 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::{KV, KVS};
use rustfs_config::{
DEFAULT_SCANNER_BITROT_CYCLE_SECS, DEFAULT_SCANNER_CACHE_SAVE_TIMEOUT_SECS, DEFAULT_SCANNER_CYCLE_MAX_DIRECTORIES,
DEFAULT_SCANNER_CYCLE_MAX_DURATION_SECS, DEFAULT_SCANNER_CYCLE_MAX_OBJECTS, DEFAULT_SCANNER_IDLE_MODE,
DEFAULT_SCANNER_MAX_CONCURRENT_DISK_SCANS, DEFAULT_SCANNER_MAX_CONCURRENT_SET_SCANS, DEFAULT_SCANNER_SPEED,
DEFAULT_SCANNER_YIELD_EVERY_N_OBJECTS, SCANNER_ALERT_EXCESS_FOLDERS, SCANNER_ALERT_EXCESS_VERSION_SIZE,
SCANNER_ALERT_EXCESS_VERSIONS, SCANNER_BITROT_CYCLE, SCANNER_CACHE_SAVE_TIMEOUT, SCANNER_CYCLE,
SCANNER_CYCLE_MAX_DIRECTORIES, SCANNER_CYCLE_MAX_DURATION, SCANNER_CYCLE_MAX_OBJECTS, SCANNER_IDLE_MODE,
SCANNER_MAX_CONCURRENT_DISK_SCANS, SCANNER_MAX_CONCURRENT_SET_SCANS, SCANNER_SPEED, SCANNER_START_DELAY,
SCANNER_YIELD_EVERY_N_OBJECTS,
};
use std::sync::LazyLock;
pub static DEFAULT_KVS: LazyLock<KVS> = LazyLock::new(|| {
KVS(vec![
KV {
key: SCANNER_SPEED.to_owned(),
value: DEFAULT_SCANNER_SPEED.to_owned(),
hidden_if_empty: false,
},
KV {
key: SCANNER_CYCLE.to_owned(),
value: String::new(),
hidden_if_empty: true,
},
KV {
key: SCANNER_START_DELAY.to_owned(),
value: String::new(),
hidden_if_empty: true,
},
KV {
key: SCANNER_CYCLE_MAX_DURATION.to_owned(),
value: DEFAULT_SCANNER_CYCLE_MAX_DURATION_SECS.to_string(),
hidden_if_empty: false,
},
KV {
key: SCANNER_CYCLE_MAX_OBJECTS.to_owned(),
value: DEFAULT_SCANNER_CYCLE_MAX_OBJECTS.to_string(),
hidden_if_empty: false,
},
KV {
key: SCANNER_CYCLE_MAX_DIRECTORIES.to_owned(),
value: DEFAULT_SCANNER_CYCLE_MAX_DIRECTORIES.to_string(),
hidden_if_empty: false,
},
KV {
key: SCANNER_BITROT_CYCLE.to_owned(),
value: DEFAULT_SCANNER_BITROT_CYCLE_SECS.to_string(),
hidden_if_empty: false,
},
KV {
key: SCANNER_IDLE_MODE.to_owned(),
value: DEFAULT_SCANNER_IDLE_MODE.to_string(),
hidden_if_empty: false,
},
KV {
key: SCANNER_CACHE_SAVE_TIMEOUT.to_owned(),
value: DEFAULT_SCANNER_CACHE_SAVE_TIMEOUT_SECS.to_string(),
hidden_if_empty: false,
},
KV {
key: SCANNER_MAX_CONCURRENT_SET_SCANS.to_owned(),
value: DEFAULT_SCANNER_MAX_CONCURRENT_SET_SCANS.to_string(),
hidden_if_empty: false,
},
KV {
key: SCANNER_MAX_CONCURRENT_DISK_SCANS.to_owned(),
value: DEFAULT_SCANNER_MAX_CONCURRENT_DISK_SCANS.to_string(),
hidden_if_empty: false,
},
KV {
key: SCANNER_YIELD_EVERY_N_OBJECTS.to_owned(),
value: DEFAULT_SCANNER_YIELD_EVERY_N_OBJECTS.to_string(),
hidden_if_empty: false,
},
KV {
key: SCANNER_ALERT_EXCESS_VERSIONS.to_owned(),
value: rustfs_config::DEFAULT_SCANNER_ALERT_EXCESS_VERSIONS.to_string(),
hidden_if_empty: false,
},
KV {
key: SCANNER_ALERT_EXCESS_VERSION_SIZE.to_owned(),
value: rustfs_config::DEFAULT_SCANNER_ALERT_EXCESS_VERSION_SIZE.to_string(),
hidden_if_empty: false,
},
KV {
key: SCANNER_ALERT_EXCESS_FOLDERS.to_owned(),
value: rustfs_config::DEFAULT_SCANNER_ALERT_EXCESS_FOLDERS.to_string(),
hidden_if_empty: false,
},
])
});