mirror of
https://github.com/rustfs/rustfs.git
synced 2026-08-08 22:33:22 +00:00
Merge branch 'main' of github.com:rustfs/s3-rustfs into feature/observability-metrics
# Conflicts: # .github/workflows/build.yml # .github/workflows/ci.yml # Cargo.lock # Cargo.toml # appauth/src/token.rs # crates/config/src/config.rs # crates/event-notifier/examples/simple.rs # crates/event-notifier/src/global.rs # crates/event-notifier/src/lib.rs # crates/event-notifier/src/notifier.rs # crates/event-notifier/src/store.rs # crates/filemeta/src/filemeta.rs # crates/notify/examples/webhook.rs # crates/utils/Cargo.toml # ecstore/Cargo.toml # ecstore/src/cmd/bucket_replication.rs # ecstore/src/config/com.rs # ecstore/src/disk/error.rs # ecstore/src/disk/mod.rs # ecstore/src/set_disk.rs # ecstore/src/store_api.rs # ecstore/src/store_list_objects.rs # iam/Cargo.toml # iam/src/manager.rs # policy/Cargo.toml # rustfs/src/admin/rpc.rs # rustfs/src/main.rs # rustfs/src/storage/mod.rs
This commit is contained in:
+47
-41
@@ -1,16 +1,14 @@
|
||||
use super::error::{is_err_config_not_found, ConfigError};
|
||||
use super::{storageclass, Config, GLOBAL_StorageClass};
|
||||
use crate::disk::RUSTFS_META_BUCKET;
|
||||
use crate::error::{Error, Result};
|
||||
use crate::store_api::{ObjectInfo, ObjectOptions, PutObjReader, StorageAPI};
|
||||
use crate::store_err::is_err_object_not_found;
|
||||
use crate::utils::path::SLASH_SEPARATOR;
|
||||
use common::error::{Error, Result};
|
||||
use http::HeaderMap;
|
||||
use lazy_static::lazy_static;
|
||||
use rustfs_utils::path::SLASH_SEPARATOR;
|
||||
use std::collections::HashSet;
|
||||
use std::io::Cursor;
|
||||
use std::sync::Arc;
|
||||
use tracing::{error, warn};
|
||||
use crate::disk::fs::SLASH_SEPARATOR;
|
||||
|
||||
pub const CONFIG_PREFIX: &str = "config";
|
||||
const CONFIG_FILE: &str = "config.json";
|
||||
@@ -41,9 +39,10 @@ pub async fn read_config_with_metadata<S: StorageAPI>(
|
||||
.get_object_reader(RUSTFS_META_BUCKET, file, None, h, opts)
|
||||
.await
|
||||
.map_err(|err| {
|
||||
if is_err_object_not_found(&err) {
|
||||
Error::new(ConfigError::NotFound)
|
||||
if err == Error::FileNotFound || matches!(err, Error::ObjectNotFound(_, _)) {
|
||||
Error::ConfigNotFound
|
||||
} else {
|
||||
warn!("read_config_with_metadata: err: {:?}, file: {}", err, file);
|
||||
err
|
||||
}
|
||||
})?;
|
||||
@@ -51,7 +50,7 @@ pub async fn read_config_with_metadata<S: StorageAPI>(
|
||||
let data = rd.read_all().await?;
|
||||
|
||||
if data.is_empty() {
|
||||
return Err(Error::new(ConfigError::NotFound));
|
||||
return Err(Error::ConfigNotFound);
|
||||
}
|
||||
|
||||
Ok((data, rd.object_info))
|
||||
@@ -85,8 +84,8 @@ pub async fn delete_config<S: StorageAPI>(api: Arc<S>, file: &str) -> Result<()>
|
||||
{
|
||||
Ok(_) => Ok(()),
|
||||
Err(err) => {
|
||||
if is_err_object_not_found(&err) {
|
||||
Err(Error::new(ConfigError::NotFound))
|
||||
if err == Error::FileNotFound || matches!(err, Error::ObjectNotFound(_, _)) {
|
||||
Err(Error::ConfigNotFound)
|
||||
} else {
|
||||
Err(err)
|
||||
}
|
||||
@@ -95,10 +94,13 @@ pub async fn delete_config<S: StorageAPI>(api: Arc<S>, file: &str) -> Result<()>
|
||||
}
|
||||
|
||||
pub async fn save_config_with_opts<S: StorageAPI>(api: Arc<S>, file: &str, data: Vec<u8>, opts: &ObjectOptions) -> Result<()> {
|
||||
let size = data.len();
|
||||
let _ = api
|
||||
.put_object(RUSTFS_META_BUCKET, file, &mut PutObjReader::new(Box::new(Cursor::new(data)), size), opts)
|
||||
.await?;
|
||||
if let Err(err) = api
|
||||
.put_object(RUSTFS_META_BUCKET, file, &mut PutObjReader::from_vec(data), opts)
|
||||
.await
|
||||
{
|
||||
error!("save_config_with_opts: err: {:?}, file: {}", err, file);
|
||||
return Err(err);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -114,12 +116,22 @@ async fn new_and_save_server_config<S: StorageAPI>(api: Arc<S>) -> Result<Config
|
||||
Ok(cfg)
|
||||
}
|
||||
|
||||
fn get_config_file() -> String {
|
||||
format!("{}{}{}", CONFIG_PREFIX, SLASH_SEPARATOR, CONFIG_FILE)
|
||||
}
|
||||
|
||||
pub async fn read_config_without_migrate<S: StorageAPI>(api: Arc<S>) -> Result<Config> {
|
||||
let data = handle_read_config(api.clone()).await?;
|
||||
let config_file = format!("{}{}{}", CONFIG_PREFIX, SLASH_SEPARATOR, CONFIG_FILE);
|
||||
let data = match read_config(api.clone(), config_file.as_str()).await {
|
||||
Ok(res) => res,
|
||||
Err(err) => {
|
||||
return if err == Error::ConfigNotFound {
|
||||
warn!("config not found, start to init");
|
||||
let cfg = new_and_save_server_config(api).await?;
|
||||
warn!("config init done");
|
||||
Ok(cfg)
|
||||
} else {
|
||||
error!("read config err {:?}", &err);
|
||||
Err(err)
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
read_server_config(api, data.as_slice()).await
|
||||
}
|
||||
@@ -127,8 +139,21 @@ pub async fn read_config_without_migrate<S: StorageAPI>(api: Arc<S>) -> Result<C
|
||||
async fn read_server_config<S: StorageAPI>(api: Arc<S>, data: &[u8]) -> Result<Config> {
|
||||
let cfg = {
|
||||
if data.is_empty() {
|
||||
let cfg_data = handle_read_config(api.clone()).await?;
|
||||
|
||||
let config_file = format!("{}{}{}", CONFIG_PREFIX, SLASH_SEPARATOR, CONFIG_FILE);
|
||||
let cfg_data = match read_config(api.clone(), config_file.as_str()).await {
|
||||
Ok(res) => res,
|
||||
Err(err) => {
|
||||
return if err == Error::ConfigNotFound {
|
||||
warn!("config not found init start");
|
||||
let cfg = new_and_save_server_config(api).await?;
|
||||
warn!("config not found init done");
|
||||
Ok(cfg)
|
||||
} else {
|
||||
error!("read config err {:?}", &err);
|
||||
Err(err)
|
||||
};
|
||||
}
|
||||
};
|
||||
// TODO: decrypt
|
||||
|
||||
Config::unmarshal(cfg_data.as_slice())?
|
||||
@@ -140,29 +165,10 @@ async fn read_server_config<S: StorageAPI>(api: Arc<S>, data: &[u8]) -> Result<C
|
||||
Ok(cfg.merge())
|
||||
}
|
||||
|
||||
async fn handle_read_config<S: StorageAPI>(api: Arc<S>) -> Result<Vec<u8>> {
|
||||
let config_file = get_config_file();
|
||||
match read_config(api.clone(), config_file.as_str()).await {
|
||||
Ok(res) => Ok(res),
|
||||
Err(err) => {
|
||||
if is_err_config_not_found(&err) {
|
||||
warn!("config not found, start to init");
|
||||
let cfg = new_and_save_server_config(api).await?;
|
||||
warn!("config init done");
|
||||
// This returns the serialized data, keeping the interface consistent
|
||||
cfg.marshal()
|
||||
} else {
|
||||
error!("read config err {:?}", &err);
|
||||
Err(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async fn save_server_config<S: StorageAPI>(api: Arc<S>, cfg: &Config) -> Result<()> {
|
||||
let data = cfg.marshal()?;
|
||||
|
||||
let config_file = get_config_file();
|
||||
let config_file = format!("{}{}{}", CONFIG_PREFIX, SLASH_SEPARATOR, CONFIG_FILE);
|
||||
|
||||
save_config(api, &config_file, data).await
|
||||
}
|
||||
|
||||
@@ -1,45 +0,0 @@
|
||||
use crate::{disk, store_err::is_err_object_not_found};
|
||||
use common::error::Error;
|
||||
|
||||
#[derive(Debug, PartialEq, thiserror::Error)]
|
||||
pub enum ConfigError {
|
||||
#[error("config not found")]
|
||||
NotFound,
|
||||
}
|
||||
|
||||
impl ConfigError {
|
||||
/// Returns `true` if the config error is [`NotFound`].
|
||||
///
|
||||
/// [`NotFound`]: ConfigError::NotFound
|
||||
#[must_use]
|
||||
pub fn is_not_found(&self) -> bool {
|
||||
matches!(self, Self::NotFound)
|
||||
}
|
||||
}
|
||||
|
||||
impl ConfigError {
|
||||
pub fn to_u32(&self) -> u32 {
|
||||
match self {
|
||||
ConfigError::NotFound => 0x01,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_u32(error: u32) -> Option<Self> {
|
||||
match error {
|
||||
0x01 => Some(Self::NotFound),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_err_config_not_found(err: &Error) -> bool {
|
||||
if let Some(e) = err.downcast_ref::<ConfigError>() {
|
||||
ConfigError::is_not_found(e)
|
||||
} else if let Some(e) = err.downcast_ref::<disk::error::DiskError>() {
|
||||
matches!(e, disk::error::DiskError::FileNotFound)
|
||||
} else if is_err_object_not_found(err) {
|
||||
return true;
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,7 @@
|
||||
use crate::error::{Error, Result};
|
||||
use rustfs_utils::string::parse_bool;
|
||||
use std::time::Duration;
|
||||
|
||||
use crate::utils::bool_flag::parse_bool;
|
||||
use common::error::{Error, Result};
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub struct Config {
|
||||
pub bitrot: String,
|
||||
@@ -42,13 +41,13 @@ fn parse_bitrot_config(s: &str) -> Result<Duration> {
|
||||
}
|
||||
Err(_) => {
|
||||
if !s.ends_with("m") {
|
||||
return Err(Error::from_string("unknown format"));
|
||||
return Err(Error::other("unknown format"));
|
||||
}
|
||||
|
||||
match s.trim_end_matches('m').parse::<u64>() {
|
||||
Ok(months) => {
|
||||
if months < RUSTFS_BITROT_CYCLE_IN_MONTHS {
|
||||
return Err(Error::from_string(format!(
|
||||
return Err(Error::other(format!(
|
||||
"minimum bitrot cycle is {} month(s)",
|
||||
RUSTFS_BITROT_CYCLE_IN_MONTHS
|
||||
)));
|
||||
@@ -56,7 +55,7 @@ fn parse_bitrot_config(s: &str) -> Result<Duration> {
|
||||
|
||||
Ok(Duration::from_secs(months * 30 * 24 * 60))
|
||||
}
|
||||
Err(err) => Err(err.into()),
|
||||
Err(err) => Err(Error::other(err)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
pub mod com;
|
||||
pub mod error;
|
||||
#[allow(dead_code)]
|
||||
pub mod heal;
|
||||
pub mod storageclass;
|
||||
|
||||
use crate::error::Result;
|
||||
use crate::store::ECStore;
|
||||
use com::{lookup_configs, read_config_without_migrate, STORAGE_CLASS_SUB_SYS};
|
||||
use common::error::Result;
|
||||
use com::{STORAGE_CLASS_SUB_SYS, lookup_configs, read_config_without_migrate};
|
||||
use lazy_static::lazy_static;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::collections::HashMap;
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
use std::env;
|
||||
|
||||
use crate::config::KV;
|
||||
use common::error::{Error, Result};
|
||||
|
||||
use super::KVS;
|
||||
use crate::config::KV;
|
||||
use crate::error::{Error, Result};
|
||||
use lazy_static::lazy_static;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::env;
|
||||
use tracing::warn;
|
||||
|
||||
/// Default parity count for a given drive count
|
||||
@@ -115,7 +113,13 @@ impl Config {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn should_inline(&self, shard_size: usize, versioned: bool) -> bool {
|
||||
pub fn should_inline(&self, shard_size: i64, versioned: bool) -> bool {
|
||||
if shard_size < 0 {
|
||||
return false;
|
||||
}
|
||||
|
||||
let shard_size = shard_size as usize;
|
||||
|
||||
let mut inline_block = DEFAULT_INLINE_BLOCK;
|
||||
if self.initialized {
|
||||
inline_block = self.inline_block;
|
||||
@@ -177,13 +181,7 @@ pub fn lookup_config(kvs: &KVS, set_drive_count: usize) -> Result<Config> {
|
||||
parse_storage_class(&ssc_str)?
|
||||
} else {
|
||||
StorageClass {
|
||||
parity: {
|
||||
if set_drive_count == 1 {
|
||||
0
|
||||
} else {
|
||||
DEFAULT_RRS_PARITY
|
||||
}
|
||||
},
|
||||
parity: { if set_drive_count == 1 { 0 } else { DEFAULT_RRS_PARITY } },
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -196,11 +194,14 @@ pub fn lookup_config(kvs: &KVS, set_drive_count: usize) -> Result<Config> {
|
||||
if let Ok(ev) = env::var(INLINE_BLOCK_ENV) {
|
||||
if let Ok(block) = ev.parse::<bytesize::ByteSize>() {
|
||||
if block.as_u64() as usize > DEFAULT_INLINE_BLOCK {
|
||||
warn!("inline block value bigger than recommended max of 128KiB -> {}, performance may degrade for PUT please benchmark the changes",block);
|
||||
warn!(
|
||||
"inline block value bigger than recommended max of 128KiB -> {}, performance may degrade for PUT please benchmark the changes",
|
||||
block
|
||||
);
|
||||
}
|
||||
block.as_u64() as usize
|
||||
} else {
|
||||
return Err(Error::msg(format!("parse {} format failed", INLINE_BLOCK_ENV)));
|
||||
return Err(Error::other(format!("parse {} format failed", INLINE_BLOCK_ENV)));
|
||||
}
|
||||
} else {
|
||||
DEFAULT_INLINE_BLOCK
|
||||
@@ -221,7 +222,7 @@ pub fn parse_storage_class(env: &str) -> Result<StorageClass> {
|
||||
|
||||
// only two elements allowed in the string - "scheme" and "number of parity drives"
|
||||
if s.len() != 2 {
|
||||
return Err(Error::msg(format!(
|
||||
return Err(Error::other(format!(
|
||||
"Invalid storage class format: {}. Expected 'Scheme:Number of parity drives'.",
|
||||
env
|
||||
)));
|
||||
@@ -229,13 +230,13 @@ pub fn parse_storage_class(env: &str) -> Result<StorageClass> {
|
||||
|
||||
// only allowed scheme is "EC"
|
||||
if s[0] != SCHEME_PREFIX {
|
||||
return Err(Error::msg(format!("Unsupported scheme {}. Supported scheme is EC.", s[0])));
|
||||
return Err(Error::other(format!("Unsupported scheme {}. Supported scheme is EC.", s[0])));
|
||||
}
|
||||
|
||||
// Number of parity drives should be integer
|
||||
let parity_drives: usize = match s[1].parse() {
|
||||
Ok(num) => num,
|
||||
Err(_) => return Err(Error::msg(format!("Failed to parse parity value: {}.", s[1]))),
|
||||
Err(_) => return Err(Error::other(format!("Failed to parse parity value: {}.", s[1]))),
|
||||
};
|
||||
|
||||
Ok(StorageClass { parity: parity_drives })
|
||||
@@ -244,14 +245,14 @@ pub fn parse_storage_class(env: &str) -> Result<StorageClass> {
|
||||
// ValidateParity validates standard storage class parity.
|
||||
pub fn validate_parity(ss_parity: usize, set_drive_count: usize) -> Result<()> {
|
||||
// if ss_parity > 0 && ss_parity < MIN_PARITY_DRIVES {
|
||||
// return Err(Error::msg(format!(
|
||||
// return Err(Error::other(format!(
|
||||
// "parity {} should be greater than or equal to {}",
|
||||
// ss_parity, MIN_PARITY_DRIVES
|
||||
// )));
|
||||
// }
|
||||
|
||||
if ss_parity > set_drive_count / 2 {
|
||||
return Err(Error::msg(format!(
|
||||
return Err(Error::other(format!(
|
||||
"parity {} should be less than or equal to {}",
|
||||
ss_parity,
|
||||
set_drive_count / 2
|
||||
@@ -264,7 +265,7 @@ pub fn validate_parity(ss_parity: usize, set_drive_count: usize) -> Result<()> {
|
||||
// Validates the parity drives.
|
||||
pub fn validate_parity_inner(ss_parity: usize, rrs_parity: usize, set_drive_count: usize) -> Result<()> {
|
||||
// if ss_parity > 0 && ss_parity < MIN_PARITY_DRIVES {
|
||||
// return Err(Error::msg(format!(
|
||||
// return Err(Error::other(format!(
|
||||
// "Standard storage class parity {} should be greater than or equal to {}",
|
||||
// ss_parity, MIN_PARITY_DRIVES
|
||||
// )));
|
||||
@@ -273,7 +274,7 @@ pub fn validate_parity_inner(ss_parity: usize, rrs_parity: usize, set_drive_coun
|
||||
// RRS parity drives should be greater than or equal to minParityDrives.
|
||||
// Parity below minParityDrives is not supported.
|
||||
// if rrs_parity > 0 && rrs_parity < MIN_PARITY_DRIVES {
|
||||
// return Err(Error::msg(format!(
|
||||
// return Err(Error::other(format!(
|
||||
// "Reduced redundancy storage class parity {} should be greater than or equal to {}",
|
||||
// rrs_parity, MIN_PARITY_DRIVES
|
||||
// )));
|
||||
@@ -281,7 +282,7 @@ pub fn validate_parity_inner(ss_parity: usize, rrs_parity: usize, set_drive_coun
|
||||
|
||||
if set_drive_count > 2 {
|
||||
if ss_parity > set_drive_count / 2 {
|
||||
return Err(Error::msg(format!(
|
||||
return Err(Error::other(format!(
|
||||
"Standard storage class parity {} should be less than or equal to {}",
|
||||
ss_parity,
|
||||
set_drive_count / 2
|
||||
@@ -289,7 +290,7 @@ pub fn validate_parity_inner(ss_parity: usize, rrs_parity: usize, set_drive_coun
|
||||
}
|
||||
|
||||
if rrs_parity > set_drive_count / 2 {
|
||||
return Err(Error::msg(format!(
|
||||
return Err(Error::other(format!(
|
||||
"Reduced redundancy storage class parity {} should be less than or equal to {}",
|
||||
rrs_parity,
|
||||
set_drive_count / 2
|
||||
@@ -298,7 +299,10 @@ pub fn validate_parity_inner(ss_parity: usize, rrs_parity: usize, set_drive_coun
|
||||
}
|
||||
|
||||
if ss_parity > 0 && rrs_parity > 0 && ss_parity < rrs_parity {
|
||||
return Err(Error::msg(format!("Standard storage class parity drives {} should be greater than or equal to Reduced redundancy storage class parity drives {}", ss_parity, rrs_parity)));
|
||||
return Err(Error::other(format!(
|
||||
"Standard storage class parity drives {} should be greater than or equal to Reduced redundancy storage class parity drives {}",
|
||||
ss_parity, rrs_parity
|
||||
)));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user